GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

EntityBuilder::getEntity()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 11
cts 11
cp 1
rs 8.5906
c 0
b 0
f 0
cc 6
eloc 11
nc 4
nop 2
crap 6
1
<?php
2
namespace izzum\statemachine;
3
4
/**
5
 * EntityBuilder is an object that builds an entity (an application domain
6
 * specific model) for a Context object so your statemachine can interact with your
7
 * domain model.
8
 * 
9
 * The entity returned is the application domain specific object that will be
10
 * injected in the Rules and Commands for a specific statemachine (eg: Order)
11
 * and can implement event handlers and callables.
12
 * A typical statemachine would use a subclass of this builder.
13
 *
14
 * The Context can build the entity by using the associated Identity object of the
15
 * Context. the entity can be obtained via the factory method EntityBuilder::getEntity().
16
 *
17
 * Of course, a specific Rule or Command can just accept the Identifier directly
18
 * and use the entity_id to generate the domain object itself. But this would
19
 * also mean that the Rules and Commands will not be specific to the applications'
20
 * problem domain but to that of the statemachine (and therefore possibly less
21
 * reusable). It is therefore advisable to let a builder build your domain model.
22
 *
23
 * The Context instance is configured with this builder class by default. It can
24
 * be configured with a subclass for your application domain if necessary (and the
25
 * configuration can be done automatically by using a concrete instance of the AbstractFactory)
26
 *
27
 * This class implements caching of the domain model/entity returned.
28
 * The builder is reusable for different statemachines (that have
29
 * a different Entity by definition). The cache will be rebuilt whenever a new
30
 * Identifier object is passed to the 'getEntity' method.
31
 *
32
 * This specific class (in contrast to subclasses) returns the Identifier itself instead of a domain model. 
33
 * This is useful because it allows us to test a lot of scenarios without side effects.
34
 * It also allows us to use the Identifier object for our rules and commands, so
35
 * you do not necessarily have to write your own entitybuilder.
36
 *
37
 * This is a prime candidate to be overriden by subclasses (if need be).
38
 * Subclass this class and override the 'build' method to return a
39
 * domain specific object of choice. The building of that domain object depends
40
 * on the information in the Context, specifically the entity_id.
41
 *
42
 * the builder can be configured via dependency injection at creation time so
43
 * the builder can make use of the injected data when it is called via 'getEntity'.
44
 *
45
 * An example of a builder would be an 'EntityBuilderOrder' class,
46
 * which would be used for a statemachine that uses rules and commands to act
47
 * upon an 'Order' object from your applation domain.
48
 *
49
 * @see Context::getEntity()
50
 * @link https://en.wikipedia.org/wiki/Builder_pattern
51
 *      
52
 * @author Rolf Vreijdenberger
53
 *        
54
 */
55
class EntityBuilder {
56
    
57
    /**
58
     * a cached instance of the built entity object
59
     * 
60
     * @var Object
61
     */
62
    protected $entity;
63
    
64
    /**
65
     * a cached instance of the used Identifier.
66
     * 
67
     * @var Identifier
68
     */
69
    protected $identifier;
70
71
    /**
72
     * Gets an application domain specific model of choice, as implemented by a
73
     * subclass.
74
     *
75
     * @param Identifier $identifier            
76
     * @param boolean $create_fresh_entity
77
     *            optional. if true, then a new instance is always created,
78
     *            else it might be cached if used for the same Identifier
79
     *            (performance).
80
     *            Since a statemachine might run multiple transitions in memory
81
     *            and alter the data in the persistence layer,
82
     *            there might be a need to refresh the entity (create it again)
83
     *            if the in memory object and the data
84
     *            in the persistence layer are not synchronized. this might
85
     *            cause rules or commands to act on
86
     *            in-memory data while it should use the persisted data.
87
     *            (an ORM should handle this automatically)
88
     *            
89
     * @return Object an object of any type, depending on the statemachine.
90
     *         This object will be used by the Rule and Command that go with a
91
     *         certain statemachine. It will be injected in the constructor of
92
     *         the
93
     *         Rule and Command.
94
     *         It implements caching so we always get the same entity instance
95
     *         on
96
     *         each call of 'getEntity' with the same Context
97
     * @see Context::getEntity()
98
     * @throws Exception
99
     */
100 46
    final public function getEntity(Identifier $identifier, $create_fresh_entity = false)
101
    {
102
        try {
103
            // lazy loading with caching.
104
            // we cache the context so we can be sure to provide
105
            // a new reference to the entity when the builder is used on a new
106
            // Identifier.
107 46
            if ($this->entity === null || $this->identifier !== $identifier || $create_fresh_entity === true) {
108
                // crate new entity and build cache
109 46
                $this->entity = $this->build($identifier);
110 45
                $this->identifier = $identifier;
111 45
            }
112 45
            return $this->entity;
113 1
        } catch(Exception $e) {
114
            // already a statemachine exception, just rethrow, it is logged
115 1
            throw $e;
116 1
        } catch(\Exception $e) {
117
            // a non statemachine type exception, wrap it so it is logged and
118
            // throw
119 1
            $e = new Exception($e->getMessage(), Exception::BUILDER_FAILURE, $e);
120 1
            throw $e;
121
        }
122
    }
123
124
    /**
125
     * the actual building function.
126
     * Override this method to return an application specific domain model.
127
     *
128
     * In an overriden function it is possible to use the state of the concrete
129
     * builder itself, which can be passed in via dependency injection at
130
     * construction time, so we have additional information on how to build the
131
     * domain object.
132
     *
133
     * @param Identifier $identifier            
134
     * @return Object an object of any type defined by the subclass
135
     */
136 40
    protected function build(Identifier $identifier)
137
    {
138
        // the default implementation returns an Identifier, which holds an id
139
        // that can be used in your rules and commands to build your domain
140
        // logic or build your domain object. specialized builders return a domain
141
        // model that will be accepted by your specialized rules/commands for
142
        // your application.
143 40
        return $identifier;
144
    }
145
146
    /**
147
     * returns the string representation
148
     * 
149
     * @return string
150
     */
151 2
    public function toString()
152
    {
153 2
        return get_class($this);
154
    }
155
156
    /**
157
     * returns the string representation
158
     * 
159
     * @return string
160
     */
161 1
    public function __toString()
162
    {
163 1
        return $this->toString();
164
    }
165
}
166