<commit_before><?php
namespace izzum\statemachine;
use izzum\statemachine\Context;
use izzum\statemachine\State;
use izzum\statemachine\Transition;
use izzum\statemachine\Exception;
/**
 * StateMachine class.
 * 
 * The statemachine is used to do transitions from state to state for
 * an entity that represents a domain object. This application domain specific 
 * object can be created by means of a Context instance and it's 
 * associated EntityBuilder.
 * 
 * This whole package strives to follow the open/closed principle, making it
 * open for extension (adding your own logic through subclassing) but closed 
 * for modification. For that purpose, we provide Loader interfaces, Builders and
 * Persistence Adapters for the backend implementation.
 * 
 * Following the same philosophy: if you want more functionality in the statemachine,
 * you can use the provided methods and override them in your subclass. multiple
 * hooks are provided.
 * 
 * The statemachine acts as a manager/service to tie all objects it works with together.
 * 
 * The statemachine should be loaded with States and Transitions, which define
 * from what state to what other state transitions are allowed. The transitions 
 * are specified by a guard clause -in the form of a business Rule- and a transition
 * Command.
 * 
 * We have provided a fully functional, normalized and indexed set of tables
 * for the postgresql relational database to function as a backend to store all
 * relevant information for a statemachine.
 * 
 * The Context object contains a reference to an underlying Entity domain model (eg:
 * an order, a customer etc) which is injected at runtime into the Rule and 
 * the Command associated with the transitions.
 * 
 * The Rule checks if the domain model (or it's derived data) applies and therefore
 * allows the transition, after which the Command is executed and can actually
 * alter data in the underlying domain models, call services etc.
 * 
 * Preferably use a subclass of the AbstractFactory to get a StateMachine.
 * 
 * All high level interactions that a client conducts with a statemachine
 * should expect exceptions. Exceptions that bubble up from this statemachine are
 * always izzum\statemachine\Exception types.
 * 
 * 
 * A good naming convention for states is to use lowercase-hypen-seperated names:
 *          new
 *          waiting-for-input
 *          starting-order-process
 *          enter-cancel-flow
 *          done
 * 
 * A good naming convention for transitions is to bind the input and exit state
 * with the string '_to_' which is done automatically by this package.
 * 
 * 
 * @author <NAME>
 * @see izzum\command\Command
 * @see izzum\rules\Rule
 * @link https://en.wikipedia.org/wiki/Finite-state_machine
 * @link https://en.wikipedia.org/wiki/Open/closed_principle
 *
 */
class StateMachine {

    /**
     * The context instance that is able to construct the stateful entity.
     *
     * @var Context
     */
    private $context;
    

    /**
     * The available states.
     * A hashmap where the key is the state name and the value is
     * the State.
     *
     * @var State[]
     */
    private $states = array();

    /**
     * The available transitions.
     * A hashmap where the key is the transition name and the value is
     * the Transition.
     *
     * @var Transition[]
     */
    private $transitions = array();
    

    
     /**
      * Preferably the AbstractFactory (or a subclass) would be used to 
      * create a statemachine associated with a stateful context that has been 
      * fully configured
      * 
      * @param Context $context a fully configured context providing all the relevant parameters/dependencies
      * 	to be able to run this statemachine for an entity.
     */
    public function __construct(Context $context, $create_fresh_entity = false)
    {
        //sets up bidirectional association
        $this->setContext($context);
    }
    
    
    /**
     * Check if a transition is possible by using the transition name (convention: <state-from>_to_<state-to>)
     * @param string $transition_name
     * @return boolean
     * @throws Exception in case something went wrong. The exceptions are logged.
     */
    public function can($transition_name)
    {
        //use the normal transition logic AND use our custom Rule based transition logic
        try {
            
            if(!$this->getCurrentState()->hasTransition($transition_name)) {
                return false;
            }
            
            $transition = $this->getTransition($transition_name);
            if($transition === null) {
                throw new Exception(sprintf("transition '%s' has not been found", 
                        $transition_name), Exception::SM_NO_TRANSITION_FOUND);
            }
            
            //possible hook
            if(!$this->checkGuard($transition)) {
                return false;<commit_msg>remove caching param<commit_after><?php
namespace izzum\statemachine;
use izzum\statemachine\Context;
use izzum\statemachine\State;
use izzum\statemachine\Transition;
use izzum\statemachine\Exception;
/**
 * StateMachine class.
 * 
 * The statemachine is used to do transitions from state to state for
 * an entity that represents a domain object. This application domain specific 
 * object can be created by means of a Context instance and it's 
 * associated EntityBuilder.
 * 
 * This whole package strives to follow the open/closed principle, making it
 * open for extension (adding your own logic through subclassing) but closed 
 * for modification. For that purpose, we provide Loader interfaces, Builders and
 * Persistence Adapters for the backend implementation.
 * 
 * Following the same philosophy: if you want more functionality in the statemachine,
 * you can use the provided methods and override them in your subclass. multiple
 * hooks are provided.
 * 
 * The statemachine acts as a manager/service to tie all objects it works with together.
 * 
 * The statemachine should be loaded with States and Transitions, which define
 * from what state to what other state transitions are allowed. The transitions 
 * are specified by a guard clause -in the form of a business Rule- and a transition
 * Command.
 * 
 * We have provided a fully functional, normalized and indexed set of tables
 * for the postgresql relational database to function as a backend to store all
 * relevant information for a statemachine.
 * 
 * The Context object contains a reference to an underlying Entity domain model (eg:
 * an order, a customer etc) which is injected at runtime into the Rule and 
 * the Command associated with the transitions.
 * 
 * The Rule checks if the domain model (or it's derived data) applies and therefore
 * allows the transition, after which the Command is executed and can actually
 * alter data in the underlying domain models, call services etc.
 * 
 * Preferably use a subclass of the AbstractFactory to get a StateMachine.
 * 
 * All high level interactions that a client conducts with a statemachine
 * should expect exceptions. Exceptions that bubble up from this statemachine are
 * always izzum\statemachine\Exception types.
 * 
 * 
 * A good naming convention for states is to use lowercase-hypen-seperated names:
 *          new
 *          waiting-for-input
 *          starting-order-process
 *          enter-cancel-flow
 *          done
 * 
 * A good naming convention for transitions is to bind the input and exit state
 * with the string '_to_' which is done automatically by this package.
 * 
 * 
 * @author <NAME>
 * @see izzum\command\Command
 * @see izzum\rules\Rule
 * @link https://en.wikipedia.org/wiki/Finite-state_machine
 * @link https://en.wikipedia.org/wiki/Open/closed_principle
 *
 */
class StateMachine {

    /**
     * The context instance that is able to construct the stateful entity.
     *
     * @var Context
     */
    private $context;
    

    /**
     * The available states.
     * A hashmap where the key is the state name and the value is
     * the State.
     *
     * @var State[]
     */
    private $states = array();

    /**
     * The available transitions.
     * A hashmap where the key is the transition name and the value is
     * the Transition.
     *
     * @var Transition[]
     */
    private $transitions = array();
    

    
     /**
      * Preferably the AbstractFactory (or a subclass) would be used to 
      * create a statemachine associated with a stateful context that has been 
      * fully configured
      * 
      * @param Context $context a fully configured context providing all the relevant parameters/dependencies
      * 	to be able to run this statemachine for an entity.
     */
    public function __construct(Context $context)
    {
        //sets up bidirectional association
        $this->setContext($context);
    }
    
    
    /**
     * Check if a transition is possible by using the transition name (convention: <state-from>_to_<state-to>)
     * @param string $transition_name
     * @return boolean
     * @throws Exception in case something went wrong. The exceptions are logged.
     */
    public function can($transition_name)
    {
        //use the normal transition logic AND use our custom Rule based transition logic
        try {
            
            if(!$this->getCurrentState()->hasTransition($transition_name)) {
                return false;
            }
            
            $transition = $this->getTransition($transition_name);
            if($transition === null) {
                throw new Exception(sprintf("transition '%s' has not been found", 
                        $transition_name), Exception::SM_NO_TRANSITION_FOUND);
            }
            
            //possible hook
            if(!$this->checkGuard($transition)) {
                return false;
{'fraction_non_alphanumeric': 0.06910197869101979, 'fraction_numerical': 0.0, 'mean_word_length': 2.708051166290444, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 19, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5304626', 'n_tokens_mistral': 2512, 'n_tokens_neox': 2410, 'n_words': 1087}