/**
  * Parse assertions which are a collection of others
  *
  * @param string    $connective How are they combined? E.g. "||"
  * @param \stdClass $annotation The annotation to create chained assertions from
  *
  * @return \AppserverIo\Doppelgaenger\Entities\Assertions\ChainedAssertion
  */
 protected function createChainedAssertion($connective, \stdClass $annotation)
 {
     // Get all the parts of the string
     $assertionArray = explode(' ', $annotation->values['typeHint']);
     // Check all string parts for the | character
     $combinedPart = '';
     $combinedIndex = 0;
     foreach ($assertionArray as $key => $assertionPart) {
         // Check which part contains the | but does not only consist of it
         if ($this->filterOrCombinator($assertionPart) && trim($assertionPart) !== $connective) {
             $combinedPart = trim($assertionPart);
             $combinedIndex = $key;
             break;
         }
     }
     // Now we have to create all the separate assertions for each part of the $combinedPart string
     $assertionList = new AssertionList();
     foreach (explode($connective, $combinedPart) as $partString) {
         // Rebuild the assertion string with one partial string of the combined part
         $tmp = $assertionArray;
         $tmp[$combinedIndex] = $partString;
         $annotation->values['typeHint'] = $partString;
         $assertion = $this->getInstance($annotation);
         if (is_bool($assertion)) {
             continue;
         } else {
             $assertionList->add($assertion);
         }
     }
     // We got everything. Create a ChainedAssertion instance
     return new ChainedAssertion($assertionList, '||');
 }
 /**
  * Invert the logical meaning of this assertion
  *
  * @return bool
  */
 public function invert()
 {
     if ($this->inverted === true) {
         $this->inverted = false;
     } else {
         $this->inverted = true;
     }
     // Iterate over all assertions and invert them.
     $iterator = $this->assertionList->getIterator();
     for ($i = 0; $i < $iterator->count(); $i++) {
         // Get the string representation of this assertion
         $iterator->current()->invert();
         // Move the iterator
         $iterator->next();
     }
     // Now invert all combinators.
     foreach ($this->combinators as $key => $combinator) {
         if (isset($this->inversionMapping[$combinator])) {
             $this->combinators[$key] = $this->inversionMapping[$combinator];
         }
     }
     return true;
 }
 /**
  * Will get the conditions for a certain assertion indicating keyword like @requires or, if configured, @param
  *
  * @param string       $docBlock         The DocBlock to search in
  * @param string       $conditionKeyword The keyword we are searching for, use assertion defining tags here!
  * @param boolean|null $privateContext   If we have to mark the parsed annotations as having a private context
  *                                       as we would have trouble finding out for ourselves.
  *
  * @return boolean|\AppserverIo\Doppelgaenger\Entities\Lists\AssertionList
  */
 public function getConditions($docBlock, $conditionKeyword, $privateContext = null)
 {
     // There are only 3 valid condition types
     if ($conditionKeyword !== Requires::ANNOTATION && $conditionKeyword !== Ensures::ANNOTATION && $conditionKeyword !== Invariant::ANNOTATION) {
         return false;
     }
     // get the annotations for the passed condition keyword
     $annotations = $this->getAnnotationsByType($docBlock, $conditionKeyword);
     // if we have to enforce basic type safety we need some more annotations
     if ($this->config->getValue('enforcement/enforce-default-type-safety') === true) {
         // lets switch the
         switch ($conditionKeyword) {
             case Ensures::ANNOTATION:
                 // we have to consider @return annotations as well
                 $annotations = array_merge($annotations, $this->getAnnotationsByType($docBlock, 'return'));
                 break;
             case Requires::ANNOTATION:
                 // we have to consider @param annotations as well
                 $annotations = array_merge($annotations, $this->getAnnotationsByType($docBlock, 'param'));
                 break;
             default:
                 break;
         }
     }
     // lets build up the result array
     $assertionFactory = new AssertionFactory();
     $result = new AssertionList();
     foreach ($annotations as $annotation) {
         // try to create assertion instances for all annotations
         try {
             $assertion = $assertionFactory->getInstance($annotation);
         } catch (\Exception $e) {
             error_log($e->getMessage());
             continue;
         }
         if ($assertion !== false) {
             // Do we already got a private context we can set? If not we have to find out four ourselves
             if ($privateContext !== null) {
                 // Add the context (wether private or not)
                 $assertion->setPrivateContext($privateContext);
             } else {
                 // Add the context (private or not)
                 $this->determinePrivateContext($assertion);
             }
             // finally determine the minimal scope of this assertion and add it to our result
             $this->determineMinimalScope($assertion);
             $result->add($assertion);
         }
     }
     return $result;
 }
 /**
  * Will flatten all conditions available at the time of the call.
  * That means this method will check which conditions make sense in an inheritance context and will drop the
  * others.
  *
  * @return bool
  */
 public function flattenConditions()
 {
     // As our lists only supports unique entries anyway, the only thing left is to check if the condition's
     // assertions can be fulfilled (would be possible as direct assertions), and flatten the contained
     // function definitions as well
     $ancestralConditionIterator = $this->ancestralInvariants->getIterator();
     foreach ($ancestralConditionIterator as $conditionList) {
         // iterate all condition lists
         $conditionListIterator = $conditionList->getIterator();
         foreach ($conditionListIterator as $assertion) {
         }
     }
     // No flatten all the function definitions we got
     $functionDefinitionIterator = $this->functionDefinitions->getIterator();
     foreach ($functionDefinitionIterator as $functionDefinition) {
         // iterate over all function definitions
         $functionDefinition->flattenConditions();
     }
     return false;
 }