Repository: ProcessMaker/nayra (php)

Issue:
Add property to skip loading non implemented elements
Add a property in BpmnDocument loader to skip loading non implemented elements instead of throwing an exception.

```
interface BpmnDocumentInterface extends StorageInterface
{
    /**
     * Get skipElementsNotImplemented property.
     *
     * If set to TRUE, skip loading elements that are not implemented
     * If set to FALSE, throw ElementNotImplementedException
     *
     * @return bool
     */
    public function getSkipElementsNotImplemented();

    /**
     * Set skipElementsNotImplemented property.
     *
     * If set to TRUE, skip loading elements that are not implemented
     * If set to FALSE, throw ElementNotImplementedException
     *
     * @param bool $skipElementsNotImplemented
     *
     * @return BpmnDocument
     */
    public function setSkipElementsNotImplemented($skipElementsNotImplemented);
}
```


Pull request description:
Add property to skip loading non implemented elements Resolves #146
This PR add a property to skip loading non implemented elements.


Patch:
diff --git a/.gitignore b/.gitignore
index 2902eaa..231bf62 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,4 @@ vendor
 composer.phar
 .DS_store
 nbproject/
-coverage/
-composer.lock
+
diff --git a/src/ProcessMaker/Nayra/Bpmn/FlowNodeTrait.php b/src/ProcessMaker/Nayra/Bpmn/FlowNodeTrait.php
index 1c3c0a3..d1ada11 100755
--- a/src/ProcessMaker/Nayra/Bpmn/FlowNodeTrait.php
+++ b/src/ProcessMaker/Nayra/Bpmn/FlowNodeTrait.php
@@ -43,13 +43,6 @@ trait FlowNodeTrait
      */
     private $states = [];
 
-    /**
-     * States classified by name
-     *
-     * @var array
-     */
-    private $statesByName = [];
-
     /**
      *
      * @var Process
@@ -153,8 +146,6 @@ trait FlowNodeTrait
     public function addState(StateInterface $state)
     {
         $this->states[] = $state;
-        $this->statesByName[$state->getName()][] = $state;
-        $state->setIndex(count($this->statesByName[$state->getName()]) - 1);
         return $this;
     }
 
@@ -168,20 +159,6 @@ trait FlowNodeTrait
         return $this->states;
     }
 
-    /**
-     * Get state by name and index.
-     *
-     * @param string $state
-     * @param string $index
-     *
-     * @return StateInterface
-     */
-    private function getStateByName($state, $index)
-    {
-        return isset($this->statesByName[$state]) && is_array($this->statesByName[$state])
-        ? $this->statesByName[$state][(int) $index] : null;
-    }
-
     /**
      * Load tokens from array.
      *
@@ -192,8 +169,11 @@ trait FlowNodeTrait
      */
     public function addToken(ExecutionInstanceInterface $instance, TokenInterface $token)
     {
-        $state = $this->getStateByName($token->getStatus(), $token->getIndex());
-        $state ? $state->addToken($instance, $token, true) : null;
+        foreach ($this->getStates() as $state) {
+            if ($state->getName() === $token->getStatus()) {
+                $state->addToken($instance, $token, true);
+            }
+        }
         return $this;
     }
 
diff --git a/src/ProcessMaker/Nayra/Bpmn/ParallelGatewayTransition.php b/src/ProcessMaker/Nayra/Bpmn/ParallelGatewayTransition.php
index b63468b..e31e329 100644
--- a/src/ProcessMaker/Nayra/Bpmn/ParallelGatewayTransition.php
+++ b/src/ProcessMaker/Nayra/Bpmn/ParallelGatewayTransition.php
@@ -43,15 +43,13 @@ class ParallelGatewayTransition implements TransitionInterface
      * The Parallel Gateway is activated if there is at least one token on
      * each incoming Sequence Flow.
      *
-     * @param \ProcessMaker\Nayra\Contracts\Engine\ExecutionInstanceInterface $executionInstance
-     *
      * @return bool
      */
     protected function hasAllRequiredTokens(ExecutionInstanceInterface $executionInstance)
     {
-        $incomingWithToken = $this->incoming()->find(function (Connection $flow) use ($executionInstance) {
-            return $flow->originState()->getTokens($executionInstance)->count() > 0;
+        $incomingWithToken = $this->incoming()->find(function(Connection $flow) use ($executionInstance) {
+            return $flow->originState()->getTokens($executionInstance)->count()>0;
         });
-        return $incomingWithToken->count() === $this->incoming()->count() && $incomingWithToken->count() > 0;
+        return $incomingWithToken->count() === $this->incoming()->count();
     }
 }
diff --git a/src/ProcessMaker/Nayra/Bpmn/StateTrait.php b/src/ProcessMaker/Nayra/Bpmn/StateTrait.php
index 2c11693..446d3eb 100755
--- a/src/ProcessMaker/Nayra/Bpmn/StateTrait.php
+++ b/src/ProcessMaker/Nayra/Bpmn/StateTrait.php
@@ -33,13 +33,6 @@ trait StateTrait
      */
     private $name;
 
-    /**
-     * State index.
-     *
-     * @var int
-     */
-    private $index;
-
     /**
      * @var FlowNodeInterface $owner
      */
@@ -96,7 +89,6 @@ trait StateTrait
         $token->setOwner($this);
         $token->setInstance($instance);
         $this->getName() ? $token->setStatus($this->getName()) : '';
-        $token->setIndex($this->getIndex());
         !$instance ?: $instance->addToken($token);
         $this->tokens->push($token);
         $this->notifyEvent(StateInterface::EVENT_TOKEN_ARRIVED, $token, $source);
@@ -118,7 +110,6 @@ trait StateTrait
         $token->setOwner($this);
         $token->setInstance($instance);
         $this->getName() ? $token->setStatus($this->getName()) : '';
-        $token->setIndex($this->getIndex());
         $instance->addToken($token);
         $this->tokens->push($token);
         $skipEvents ?: $this->notifyEvent(StateInterface::EVENT_TOKEN_ARRIVED, $token, $source);
@@ -162,29 +153,6 @@ trait StateTrait
         return $this;
     }
 
-    /**
-     * Get state index
-     *
-     * @return int
-     */
-    public function getIndex()
-    {
-        return $this->index;
-    }
-
-    /**
-     * Set state name.
-     *
-     * @param int $index
-     *
-     * @return $this
-     */
-    public function setIndex($index)
-    {
-        $this->index = $index;
-        return $this;
-    }
-
     /**
      * Set the owner node.
      *
diff --git a/src/ProcessMaker/Nayra/Bpmn/TokenTrait.php b/src/ProcessMaker/Nayra/Bpmn/TokenTrait.php
index ce0bb0d..c0ac315 100755
--- a/src/ProcessMaker/Nayra/Bpmn/TokenTrait.php
+++ b/src/ProcessMaker/Nayra/Bpmn/TokenTrait.php
@@ -105,29 +105,6 @@ trait TokenTrait
         return $this;
     }
 
-    /**
-     * Get token internal index.
-     *
-     * @return index
-     */
-    public function getIndex()
-    {
-        return $this->getProperty(TokenInterface::BPMN_PROPERTY_INDEX, 0);
-    }
-
-    /**
-     * Set token internal index.
-     *
-     * @param int $index
-     *
-     * @return $this
-     */
-    public function setIndex($index)
-    {
-        $this->setProperty(TokenInterface::BPMN_PROPERTY_INDEX, $index);
-        return $this;
-    }
-
     /**
      * Get the owner element of the token.
      *
diff --git a/src/ProcessMaker/Nayra/Contracts/Bpmn/StateInterface.php b/src/ProcessMaker/Nayra/Contracts/Bpmn/StateInterface.php
index 2530bfc..97faf36 100755
--- a/src/ProcessMaker/Nayra/Contracts/Bpmn/StateInterface.php
+++ b/src/ProcessMaker/Nayra/Contracts/Bpmn/StateInterface.php
@@ -71,22 +71,6 @@ interface StateInterface extends TraversableInterface, ObservableInterface, Conn
      */
     public function setName($name);
 
-    /**
-     * Get state index
-     *
-     * @return int
-     */
-    public function getIndex();
-
-    /**
-     * Set state name.
-     *
-     * @param int $index
-     *
-     * @return $this
-     */
-    public function setIndex($index);
-
     /**
      * Set the owner node.
      *
diff --git a/src/ProcessMaker/Nayra/Contracts/Bpmn/TokenInterface.php b/src/ProcessMaker/Nayra/Contracts/Bpmn/TokenInterface.php
index f2e46e5..76e1c5d 100755
--- a/src/ProcessMaker/Nayra/Contracts/Bpmn/TokenInterface.php
+++ b/src/ProcessMaker/Nayra/Contracts/Bpmn/TokenInterface.php
@@ -13,7 +13,6 @@ interface TokenInterface extends EntityInterface
 {
     const BPMN_PROPERTY_MESSAGE = 'message';
     const BPMN_PROPERTY_STATUS = 'status';
-    const BPMN_PROPERTY_INDEX = 'index';
 
     /**
      * Get the owner of the token.
@@ -54,22 +53,6 @@ interface TokenInterface extends EntityInterface
      */
     public function setStatus($status);
 
-    /**
-     * Get token internal index.
-     *
-     * @return index
-     */
-    public function getIndex();
-
-    /**
-     * Set token internal index.
-     *
-     * @param int $index
-     *
-     * @return $this
-     */
-    public function setIndex($index);
-
     /**
      * Set the owner execution instance of the token.
      *
diff --git a/src/ProcessMaker/Nayra/Contracts/Storage/BpmnDocumentInterface.php b/src/ProcessMaker/Nayra/Contracts/Storage/BpmnDocumentInterface.php
index 966764c..4bebb69 100644
--- a/src/ProcessMaker/Nayra/Contracts/Storage/BpmnDocumentInterface.php
+++ b/src/ProcessMaker/Nayra/Contracts/Storage/BpmnDocumentInterface.php
@@ -74,6 +74,29 @@ interface BpmnDocumentInterface extends StorageInterface
      * @return bool
      */
     public function hasElementInstance($id);
+
+    /**
+     * Get skipElementsNotImplemented property.
+     *
+     * If set to TRUE, skip loading elements that are not implemented
+     * If set to FALSE, throw ElementNotImplementedException
+     *
+     * @return bool
+     */
+    public function getSkipElementsNotImplemented();
+
+    /**
+     * Set skipElementsNotImplemented property.
+     *
+     * If set to TRUE, skip loading elements that are not implemented
+     * If set to FALSE, throw ElementNotImplementedException
+     *
+     * @param bool $skipElementsNotImplemented
+     *
+     * @return BpmnDocument
+     */
+    public function setSkipElementsNotImplemented($skipElementsNotImplemented);
+
     /**
      * Validate document with BPMN schemas.
      *
diff --git a/src/ProcessMaker/Nayra/Storage/BpmnDocument.php b/src/ProcessMaker/Nayra/Storage/BpmnDocument.php
index 9272e61..f6b8740 100644
--- a/src/ProcessMaker/Nayra/Storage/BpmnDocument.php
+++ b/src/ProcessMaker/Nayra/Storage/BpmnDocument.php
@@ -76,6 +76,11 @@ class BpmnDocument extends DOMDocument implements BpmnDocumentInterface
      */
     private $factory;
 
+    /**
+     * @var bool $skipElementsNotImplemented
+     */
+    private $skipElementsNotImplemented = false;
+
     /**
      * BPMNValidator errors.
      *
@@ -520,6 +525,35 @@ class BpmnDocument extends DOMDocument implements BpmnDocumentInterface
         return !empty($element) && !empty($element->getBpmnElementInstance());
     }
 
+    /**
+     * Get skipElementsNotImplemented property.
+     *
+     * If set to TRUE, skip loading elements that are not implemented
+     * If set to FALSE, throw ElementNotImplementedException
+     *
+     * @return bool
+     */
+    public function getSkipElementsNotImplemented()
+    {
+        return $this->skipElementsNotImplemented;
+    }
+
+    /**
+     * Set skipElementsNotImplemented property.
+     *
+     * If set to TRUE, skip loading elements that are not implemented
+     * If set to FALSE, throw ElementNotImplementedException
+     *
+     * @param bool $skipElementsNotImplemented
+     *
+     * @return BpmnDocument
+     */
+    public function setSkipElementsNotImplemented($skipElementsNotImplemented)
+    {
+        $this->skipElementsNotImplemented = $skipElementsNotImplemented;
+        return $this;
+    }
+
     /**
      * Get Activity instance by id.
      *
diff --git a/src/ProcessMaker/Nayra/Storage/BpmnElement.php b/src/ProcessMaker/Nayra/Storage/BpmnElement.php
index 82facb5..e1a324c 100644
--- a/src/ProcessMaker/Nayra/Storage/BpmnElement.php
+++ b/src/ProcessMaker/Nayra/Storage/BpmnElement.php
@@ -6,10 +6,10 @@ use DOMAttr;
 use DOMElement;
 use ProcessMaker\Nayra\Contracts\Bpmn\CallableElementInterface;
 use ProcessMaker\Nayra\Contracts\Bpmn\EntityInterface;
+use ProcessMaker\Nayra\Contracts\Bpmn\FlowNodeInterface;
 use ProcessMaker\Nayra\Contracts\Storage\BpmnElementInterface;
 use ProcessMaker\Nayra\Exceptions\ElementNotImplementedException;
 use ProcessMaker\Nayra\Exceptions\NamespaceNotImplementedException;
-use ProcessMaker\Nayra\Contracts\Bpmn\FlowNodeInterface;
 
 /**
  * Description of BpmnFileElement
@@ -37,7 +37,9 @@ class BpmnElement extends DOMElement implements BpmnElementInterface
         if (!array_key_exists($this->namespaceURI, $map)) {
             throw new NamespaceNotImplementedException($this->namespaceURI);
         }
-        if (!array_key_exists($this->localName, $map[$this->namespaceURI])) {
+        if (!array_key_exists($this->localName, $map[$this->namespaceURI]) && $this->ownerDocument->getSkipElementsNotImplemented()) {
+            return null;
+        } elseif (!array_key_exists($this->localName, $map[$this->namespaceURI])) {
             throw new ElementNotImplementedException($this->localName);
         }
         if ($map[$this->namespaceURI][$this->localName] === BpmnDocument::SKIP_ELEMENT) {


Test patch:
diff --git a/tests/Feature/Engine/LoadFromBPMNFileTest.php b/tests/Feature/Engine/LoadFromBPMNFileTest.php
index f7a36ca..5594fb2 100644
--- a/tests/Feature/Engine/LoadFromBPMNFileTest.php
+++ b/tests/Feature/Engine/LoadFromBPMNFileTest.php
@@ -539,6 +539,30 @@ class LoadFromBPMNFileTest extends EngineTestCase
         $bpmnRepository->getActivity('_2');
     }
 
+    /**
+     * Test skip loading of non implemented elements.
+     *
+     */
+    public function testSkipCustomElementNotImplemented()
+    {
+        //Load a BpmnFile Repository
+        $bpmnRepository = new BpmnDocument();
+        $bpmnRepository->setSkipElementsNotImplemented(true);
+        $bpmnRepository->setEngine($this->engine);
+        $bpmnRepository->setFactory($this->repository);
+        $bpmnRepository->setBpmnElementMapping('http://www.processmaker.org/spec/PM/20100607/MODEL', 'task', [
+                ActivityInterface::class,
+                [
+                    FlowNodeInterface::BPMN_PROPERTY_INCOMING => ['n', [BpmnDocument::BPMN_MODEL, FlowNodeInterface::BPMN_PROPERTY_INCOMING]],
+                    FlowNodeInterface::BPMN_PROPERTY_OUTGOING => ['n', [BpmnDocument::BPMN_MODEL, FlowNodeInterface::BPMN_PROPERTY_OUTGOING]],
+                ]
+            ]);
+        $bpmnRepository->load(__DIR__ . '/files/CustomElements.bpmn');
+        
+        //Try to get custom element
+        $bpmnRepository->getActivity('PROCESS_1');
+    }
+
     /**
      * Test to get a missing BPMN element.
      *