I tried to create a rather complex domain called Vacancy, here is the details:
Vacancy.php
class Vacancy extends AbstractEntity implements AggregateRootInterface {
private $employer;
private $title;
private $employerInformation;
private $position;
private $category;
private $employmentInformation;
private $hideSalary = false;
private $requiredPerson = 1;
private $yearsExp = 0;
private $location;
private $benefits;
private $qualification;
private $details;
private $postedOn;
private $lastPostPackage;
private $expiredOn;
private $visible = true;
public function __construct(
PackageOnHand $package,
$title,
Position $position,
JobCategory $category,
$employerInformation,
EmploymentInformation $employmentInformation,
City $location,
$qualification
) {
parent::__construct();
$this->employer = $package->getEmployer();
$this->title = $title;
$this->position = $position;
$this->category = $category;
$this->employerInformation = $employerInformation;
$this->employmentInformation = $employmentInformation;
$this->location = $location;
$this->setQualification($qualification);
$this->benefits = new ArrayCollection();
$this->details = new ArrayCollection();
}
// Bunch of setters, getters and methods I don't even want to mention
}
The EmploymentInformation class is already encapsulates 4 required parameters, which makes it an entity (and I personally feels wrong about it).
As can be seen, this particular domain model's constructor is extended to 8 parameters, not to mention the possibility to add some more.
The problem is, all of those parameters does required to make a single Vacancy into it's valid state.
I've read about Builder Pattern in this SO question, but it suggested that the Builder class is made into a nested class inside, which can't be done in PHP.
Is there any other pattern I can use to clear up constructor bloat?
There might be several issues with your class.
Firstly, most likely you are violating SRP (single responsibility principle). Watch this: http://vimeo.com/43592685
Second. In constructor you pass things that are needed for all methods to work. Since you didn't specify any methods (getters and setters are not a methods I'm talking about) I can't tell if you need all of these parameters. In DDD your methods should mirror UL (ubiquitos language). For now it looks just like a container for data (anemic entity).
Builder pattern can be implemented in a various ways, you don't need nested classes. But builders are used for a different purpose, you should't use it here. I would simply make a factory for that.
I would also think about using "a specification" pattern here.
Related
Say I have a very simple CRUD system in PHP to manage a database. Say it holds a list of products. Using Doctrine ORM, I'd like to query the database and view/edit/add records. According to the Getting Started manual,
When creating entity classes, all of the fields should be protected or
private (not public), with getter and setter methods for each one
(except $id). The use of mutators allows Doctrine to hook into calls
which manipulate the entities in ways that it could not if you just
directly set the values with entity#field = foo;
This is the sample provided:
// src/Product.php
class Product
{
/**
* #var int
*/
protected $id;
/**
* #var string
*/
protected $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
// Recording a new title
$product->setName("My new name");
$db->persist($product);
$db->flush();
// Echoing the title
echo $product->getName();
However, this seems overly complicated. Say I don't have a need to hook into calls to manipulate entities, as explained in the manual. I can make this code much shorter and do this:
// src/Product.php
class Product
{
/**
* #var int
*/
public $id;
/**
* #var string
*/
public $name;
}
This would allow things like this:
$product = $db->getRepository('Product')->find(1);
// Recording a new name
$product->name = "My new title";
$db->persist($product);
$db->flush();
// Echoing the title
echo $product->name;
The advantages are:
Always using the exact same name
No extra setters and getters in the entity class
What is the disadvantage of using this? Am I taking certain risks here?
Say I don't have a need to hook into calls to manipulate entities, as explained in the manual.
You do not need to hook into these calls, but Doctrine does. Doctrine internally overrides these getters and setters to implement an ORM as transparently as possible.
Yes, it is overly complicated, but that is the PHP language at fault and not Doctrine. There is nothing inherently wrong with using public properties, it is just that the PHP language does not allow creating custom getters/setters the way some other languages do (such as Kotlin, C#).
What does Doctrine do exactly? It generates so-called Proxy objects to implement lazy loading. These objects extend your class and override certain methods.
For your code:
// src/Product.php
class Product
{
/**
* #var int
*/
protected $id;
/**
* #var string
*/
protected $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
Doctrine might generate:
class Product extends \YourNamespace\Product implements \Doctrine\ORM\Proxy\Proxy
{
// ... Lots of generated methods ...
public function getId(): int
{
if ($this->__isInitialized__ === false) {
return (int) parent::getId();
}
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []);
return parent::getId();
}
public function getName(): string
{
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getName', []);
return parent::getName();
}
// ... More generated methods ...
}
(What this does exactly is not the point, the point is that Doctrine MUST be able to override getters and setters to implement an ORM)
To see for yourself, inspect the generated Proxy objects in the proxy directory of Doctrine. See the Advanced Configuration section for more info on configuring the proxy directory. Also see Working with Objects for more info on Proxy objects and how Doctrine utilizes them.
Why not use public entity classes in Doctrine?
Actually what you are asking is:
Where does this getters/setters come from?
It comes from the Encapsulation in OOP.
so, what is encapsulation?
It’s the way we define the visibility of our properties and methods. When you’re creating classes, you have to ask yourself what properties and methods can be accessed outside of the class.
Let’s say we had a property named id. If a class extends your class, is it allowed to manipulate and access id directly? What if someone creates an instances of your class? Are they allowed to manipulate and access id?
NO! They should not be able to reach the id attribute directly.
Why not?
Example: What happens if you only accept Invoice Ids which start with "IX" and other classes have access to your class and they set the invoice_id directly?
What happens if they accidentally set the invoice_id to "XX12345"?
of course, you cannot do anything (like validating the input), because you are using public properties and no setters.
but if you had a setter method in your class, you could just do
private $invoiceId;
public function setInvoiceId($invoiceId)
{
if (is_null($invoiceId) || preg_match("#^IX(.*)$#i", $invoiceId) === 0)
return false;
$this->invoiceId = $invoiceId;
return $this;
}
I hope it was clear enought. I will try to extend the answer
Is it normal to not defined variable in class properties, but indicate at once in constructor ?
I just learn OOP, and found that example:
class Foo {
public function __construct($name) {
$this->_name = $name;
}
}
and it works, i can use this variable
$objFoo = new Foo('Fido');
echo $objFoo->_name; //output 'Fido'
But in class properties, there has no defined variable $_name, like public $_name in start of class.
So if we dont define it directly, it will be created automatically throught constructor ? And is it real to set scope for variable that way, protected, private ?
In PHP, this is called "object overloading", you can add/set new properties on (almost) any instance on the fly. However, you shouldn't do this. These properties make your code more error prone, less maintainable and overloaded properties that are added are slower: details here.
Pre-declaring properties allows for better documentation, your IDE's auto-completion function is actually worth something then, and you don't get in the habit of relying on something that doesn't always work. I tend to write my data models along these lines:
class DataModel
{
/**
* #var int
*/
protected $id = null;
/**
* #var string
*/
protected $name = null;
/**
* #var \DateTime
*/
protected $birthday = null;
public function __construct(array $data)
{}//set values
public function __set($name, $value)
{
throw new \BadMethodCallException('Do not attempt overloading, use getters and setter');
}
}
I define getters and setters for all of the properties, to ensure type safety, and validation can be done. I expressly disable overloading because of the risk of typo's, and difficult debugging. I often find myself disabling __sleep, __serialize and all those magic methods for pretty much the same reason.
Creating object members on the fly, meaning just assigning a value to it without declaring the member, is not limited to the constructor method. It can be done from inside of every method in the class or even from outside of the class, like this:
$c = new stdClass();
$c->foo = "bar";
While there are still a few use cases for this, I suggest to declare every class member explicitly in the head of the class. Also you will want in most cases to declare class members as protected or even private which requires an explicit declaration anyway.
I've been reading through Effective Java by Joshua Bloch. I also develop in PHP and I wanted to implement the builder pattern outlined in item 2, but PHP doesn't have inner classes. Is there any way to achieve this pattern in PHP, keeping the constructor for the product private?
Since PHP does not support inner classes, there must be a public method on the product class that creates an instance of it. Consider the following PHP classes:
<?php
class NutritionalFactsBuilder {
private $sodium;
private $fat;
private $carbo;
/**
* It is preferred to call NutritionalFacts::createBuilder
* to calling this constructor directly.
*/
function __construct($s) {
$this->sodium = $s;
}
function fat($f) {
$this->fat = $f;
return $this;
}
function carbo($c) {
$this->carbo = $c;
return $this;
}
function getSodium() {
return $this->sodium;
}
function getFat() {
return $this->fat;
}
function getCarbo() {
return $this->carbo;
}
function build() {
return new NutritionalFacts($this);
}
}
class NutritionalFacts {
private $sodium;
private $fat;
private $carbo;
static function createBuilder($s) {
return new NutritionalFactsBuilder($s);
}
/**
* It is preferred to call NutritionalFacts::createBuilder
* to calling this constructor directly.
*/
function __construct(NutritionalFactsBuilder $b) {
$this->sodium = $b->getSodium();
$this->fat = $b->getFat();
$this->carbo = $b->getCarbo();
}
}
echo '<pre>';
var_dump(NutritionalFacts::createBuilder(10)->fat(23)->carbo(1)->build());
echo '</pre>';
?>
Note that in the above example the constructor of NutritionalFacts is public. Due to the constraints of the language, however, having a public constructor is not at all bad. Since one must call the constructor with a NutritionalFactsBuilder, there are only a limited number of ways to instantiate NutritionalFacts. Let's compare them:
// NutritionalFacts Instantiation #0
$nfb = new NutritionalFactsBuilder(10);
$nfb = $nfb->fat(23)->carbo(1);
$nf0 = new NutritionalFacts($nfb);
// NutritionalFacts Instantiation #1
$nfb = new NutritionalFactsBuilder(10);
$nf1 = $nfb->fat(23)->carbo(1)->build();
// NutritionalFacts Instantiation #2
$nf2 = NutritionalFacts::createBuilder(10)->fat(23)->carbo(1)->build();
// NutritionalFacts Instantiation #3
// $nf3 = (new NutritionalFactsBuilder(10))->fat(23)->carbo(1)->build();
To leverage function chaining to its fullest extent, "NutritionalFacts Instantiation #2" is the preferred usage.
"NutritionalFacts Instantiation #3" shows another nuance of PHP syntax; one cannot chain a method on a newly instantiated object. Update: In PHP 5.4.0, there is now support for the syntax in "NutritionalFacts Instantiation #3." I haven't tested it yet though.
Making the Constructor Private
You could make the constructor private, but I wouldn't recommend it. If the constructor were made private, a public, static factory method would be necessary, as in the following code snippet. Looking at the below code, we might as well make the constructor public instead of introducing indirection just to make the constructor private.
class NutritionalFacts {
private $sodium;
private $fat;
private $carbo;
static function createBuilder($s) {
return new NutritionalFactsBuilder($s);
}
static function createNutritionalFacts($builder) {
return new NutritionalFacts($builder);
}
private function __construct($b) {
$this->sodium = $b->getSodium();
$this->fat = $b->getFat();
$this->carbo = $b->getCarbo();
}
}
Immutability is good and definitely something to strive for, this applies to PHP as it does to any other language no matter what. Immutability gives you certainty that you do not have to fear that the instance suddenly mutates without you knowing.
That being said, there is an easy way to implement the builder pattern to build immutable objects even without inner classes (although available now with PHP 7).
The first important building block is a common base class for the actual immutable class and the builder. This allows them to access each others properties. Something that is also known as friend classes or solvable through extended access modifiers in other languages, something PHP does not have. Note that the clone ability is restricted, it makes no sense to clone immutable objects but more about the protected modifier later.
abstract class NutritionalFactData {
protected $sodium = 0;
protected $fat = 0;
protected $carbo = 0;
protected function __clone() {}
}
The immutable class is straight forward with stupid example getters and the default constructor. Note the final modifier for the class itself and that it is not aware of the builder class at all.
final class NutritionalFacts extends NutritionalFactData {
public function getSodium() {
return $this->sodium;
}
public function getFat() {
return $this->fat;
}
public function getCarbo() {
return $this->carbo;
}
}
Now the actual builder implementation. Note how we operate directly on an instance of the immutable class and that we simply clone it when the build method is called. This ensures that later calls to the setters of the builder will not alter the instances that were previously built and ensures that no receiver of such an instance has to take care of the cloning on their own.
final class NutritionalFactBuilder extends NutritionalFactData {
private $nutritional_facts;
public function __construct() {
$this->nutritional_facts = new NutritionalFacts;
}
public function build() {
return clone $this->nutritional_facts;
}
public function setSodium($sodium) {
$this->nutritional_facts->sodium = $sodium;
return $this;
}
public function setFat($fat) {
$this->nutritional_facts->fat = $fat;
return $this;
}
public function setCarbo($carbo) {
$this->nutritional_facts->carbo = $carbo;
return $this;
}
}
For completeness a usage example:
var_dump(
(new NutritionalFactBuilder)
->setSodium(21)
->setFat(42)
->build()
);
Here is the runnable example.
I think it is obvious that we can now implement as many builder implementations as we like. Not really needed for this example but we can think of other constructs where many more properties are involved. Like the car example given on (the very bad) builder pattern article of Wikipedia. We might want to have pre-configured builders for known car categories.
abstract class CarParts {}
final class Car extends CarParts {}
abstract class CarBuilder extends CarParts {
abstract public function build(): Car;
}
final class CompactCarBuilder extends CarBuilder {}
final class SportsCarBuilder extends CarBuilder {}
final class RaceCarBuilder extends CarBuilder {}
In the Gang of Four description of the Builder pattern, you'll find no requirement for an inner class. The key feature is the aggregate relationship between the Director and Builder interface that provide a "blueprint" for putting together a series of Product implementations.
You can find lots of examples of the PHP Builder pattern here:
http://www.php5dp.com/category/design-patterns/builder/
Cheers,
Bill
I'm searching for this for quite some time now.
I saw few similar questions but not sure if they apply with doctrine2 and this problem.
I'm trying to get started with CodeIgniter2 and Doctrine2, and I'm having some problems, I'm not OOP guru in php.
I would like to have MainObject that will contains methods for CRUD and few others, and I want objects to extend that class and use parent's methods, but with child's properties. Since Doctrine2 uses Private Properties for objects, I cannot access these methods from parent class. For example:
Class MainObject{
public function validateFields(){
//go over each field and validate/update if needed
}
public function store(){
// do some validation, some logic, store, etc...
}
}
Class User extends MainObject{
/**
* #Column(type="string", length=32, unique=true, nullable=false)
*/
private $username;
/**
* #Column(type="string", length=64, nullable=true)
*/
private $email;
}
Now, I would like to just call
$user = new User();
//set properties, somehow
$user-__set($something);
//call validation or store or some method from the parent that will interact with child properties
$user->validate();
$user->store();
$user->uploadImage();
$user->formatPropertiesForSomethingSpecial();
I'm almost there to do this by using the ReflectionClass but I'm not sure that I'm doing this the right way?
Or is there a way to have MainObject with all this methods, and then just pass User to it so it can do what it should do with user, is perhaps that the 'righter' approach? I don't think it will allow me to do something with Private properties from the user, but I guess that User can have its own getters and setters?
I'm working with semi-oop in php for years, but this is something new for me, so thanks for any advice, tutorial, url, critique, anything.
The easiest (and correct) way is to use a setter.
Class User extends MainObject{
private $username;
private $email;
public function set_username($username) {
$this->username = $username;
}
}
If you want to make it less verbose, use a general purpose setter in the parent:
Class MainObject{
public function validateFields(){
}
public function store(){
}
public function set($data) {
foreach ($data as $key => $value) {
if (property_exists($this, $key)) {
$this->$key = $value;
}
}
}
}
// Example
$user = new User();
$data = array('username' => 'foo', 'email' => 'bar#bar.bar');
$user->set($data);
$user->validate();
$user->store();
You will need at least PHP >= 5.1 for the second method.
I just brushed up on my visibility documentation. You'll need to use a protected property instead of private, or write all of your setters in the child class.
I'm not sure if the title is the best way to describe this question.
This book - http://apress.com/book/view/9781590599099 - illustrates an implementation of the Unit of Work pattern. It goes a little something like this.
class UoW(){
private array $dirty;
private array $clean;
private array $new;
private array $delete;
public static function markClean(Entity_Class $Object){
//remove the class from any of the other arrays, add it to the clean array
}
public static function markDirty(Entity_Class $Object){
//remove the class from any of the other arrays, add it to the dirty array
}
public static function markNew(Entity_Class $Object){
//add blank entity classes to the new array
}
public static function markDelete(Entity_Class $Object){
//remove the class reference from other arrays, mark for deletion
}
public function commit(){
//perform all queued operations, move all objects into new array, remove any deleted objects
}
}
class MyMapper(){
public function setName($value){
$this->name = $value;
UoW::markDirty($this);//here's where the problem is
}
}
(Ignoring issues of static calls and dependencies for a moment)
The author notes that this implementation requires the coder to insert the relevant UoW marking methods, and that this elective honouring of the pattern can lead to errors. Now, taking on board the pros and cons of concrete accessors, you could perhaps automate the UoW invocation like this:
public function __set($key,$value){
//check to see if this is valid property for this class
//assuming the class has an array defining allowed properties
if(property_exists($this,$key)){
$this->$key = $value;
UoW::markDirty($this);
/*
* or alternatively use an observer relationship
* i.e. $this->notify();
* assuming the UoW has been attached prior to this operation
*/
}
}
So, my question is, how would you go about guaranteeing the appropriate UoW method was called when setting properties on a Domain Object?
The best approach I've found is to declare the properties "protected" and then use PHPDoc comments to "expose" them as public properties. Something like:
/**
* #property string $prop
*/
class Foo extends UoW {
protected $prop = "foo";
public function __set($name, $value) {
if (property_exists($this, $name)) {
$this->$name = $value;
$this->markDirty();
}
}
}
This will cause your IDE and most tools to pick up that Foo->prop is a property, while ensuring the dirty mark gets set.