Skip to content
CompositeEvaluator.php 6.9 KiB
Newer Older
<?php

/**
 * Class CompositeEvaluator
 *
 * Date: 07.01.14
 * Time: 13:27
 * @author Thomas Joußen <tjoussen@databay.de>
Michael Jansen's avatar
Michael Jansen committed
 */
class CompositeEvaluator
{

    /**
     * @var ilParserQuestionProvider
     */
    protected $object_loader;

    /**
     * @var ilFormATestSession
     */
    protected $session;

    /**
     * @param ilParserQuestionProvider $object_loader
     * @param ilFormATestSession $session
     */
    public function __construct($object_loader, $session)
    {
        $this->object_loader = $object_loader;
        $this->session = $session;
    }

    /**
     * @param AbstractComposite $composite
     *
     * @return bool
     */
    public function evaluate(AbstractComposite $composite)
    {
        if (is_array($composite->nodes) && count($composite->nodes) > 0) {
            $composite->nodes[0] = $this->evaluate($composite->nodes[0]);
            $composite->nodes[1] = $this->evaluate($composite->nodes[1]);
            $composite = $this->evaluateSubTree($composite);
        }
        return $composite;
    }

    /**
     * @param AbstractComposite $composite
     *
     * @return bool
     */
    private function evaluateSubTree(AbstractComposite $composite)
    {
        $result = false;
        if ($composite->nodes[0] instanceof ExpressionInterface &&
            $composite->nodes[1] instanceof ExpressionInterface
        ) {
            $question = $this->object_loader->getQuestion($composite->nodes[0]->getQuestionIndex());
            $rightNode = $composite->nodes[1];

            $index = ($composite->nodes[0] instanceof ResultOfAnswerOfQuestionExpression)? $composite->nodes[0]->getAnswerIndex(): null;

            $solutions = $question->getUserQuestionResult($this->session->getActiveId(), $this->session->getPass());

            if ($question instanceof assClozeTest) {
                // @todo for Thomas J.: Move to interface / implement in concrete class (req. for future releases)
                /**
                 * @var $gap assClozeGap
                 * @var $answer assAnswerCloze
                 */
                $result = $solutions->getSolutionForKey($index);
                $gap = $question->getAvailableAnswerOptions($index - 1);

                if ($rightNode instanceof StringResultExpression) {
                    if ($gap->getType() == 1) {
                        $answer = $gap->getItem($result['value'] - 1);
                        $solutions->removeByKey($index);
                        $solutions->addKeyValue($index, $answer->getAnswertext());
                    }
                } elseif (
                    $rightNode instanceof PercentageResultExpression &&
                    $composite->nodes[0] instanceof ResultOfAnswerOfQuestionExpression) {
                    /**
                     * @var $answers assAnswerCloze[]
                     */
                    $answers = $gap->getItems(new ilArrayElementShuffler());
                    $max_points = 0;
                    foreach ($answers as $answer) {
                        if ($max_points < $answer->getPoints()) {
                            $max_points = $answer->getPoints();
                        }
                    }

                    $item = null;
                    $reached_points = null;
                    // @todo for Thomas J.: Maybe handle identical scoring for every type
                    switch ($gap->getType()) {
                        case CLOZE_TEXT:
                            for ($order = 0; $order < $gap->getItemCount(); $order++) {
                                $answer = $gap->getItem($order);
                                $item_points = $question->getTextgapPoints($answer->getAnswertext(), $result['value'], $answer->getPoints());
                                if ($item_points > $reached_points) {
                                    $reached_points = $item_points;
                                }
                            }
                            break;

                        case CLOZE_NUMERIC:
                            for ($order = 0; $order < $gap->getItemCount(); $order++) {
                                $answer = $gap->getItem($order);
                                $item_points = $question->getNumericgapPoints($answer->getAnswertext(), $result["value"], $answer->getPoints(), $answer->getLowerBound(), $answer->getUpperBound());
                                if ($item_points > $reached_points) {
                                    $reached_points = $item_points;
                                }
                            }
                            break;

                        case CLOZE_SELECT:
                            if ($result['value'] != null) {
                                $answer = $gap->getItem($result['value'] - 1);
                                $reached_points = $answer->getPoints();
                            }
                            break;
                    }

                    $percentage = 0;
                    if ($max_points != 0 && $reached_points !== null) {
                        $percentage = (int) (($reached_points / $max_points) * 100);
                    }
                    $solutions->setReachedPercentage($percentage);
                }
            }

            if (
                $question instanceof assFormulaQuestion &&
                $rightNode instanceof PercentageResultExpression &&
                $composite->nodes[0] instanceof ResultOfAnswerOfQuestionExpression
            ) {
                // @todo for Thomas J.: Move to interface / implement in concrete class (req. for future releases)
                $result = $solutions->getSolutionForKey($index);
                $answer = $question->getAvailableAnswerOptions($index - 1);

                $unit = $solutions->getSolutionForKey($index . "_unit");
                $key = null;
                if (is_array($unit)) {
                    $key = $unit['value'];
                }

                $max_points = $answer->getPoints();
                $points = $answer->getReachedPoints($question->getVariables(), $question->getResults(), $result["value"], $key, $question->getUnitrepository()->getUnits());

                $percentage = 0;
                if ($max_points != 0) {
                    $percentage = (int) (($points / $max_points) * 100);
                }
                $solutions->setReachedPercentage($percentage);
            }

            $result = $rightNode->checkResult($solutions, $composite->getPattern(), $index);
        } else {
            switch ($composite->getPattern()) {
                case "&":
                    $result = $composite->nodes[0] && $composite->nodes[1];
                    break;
                case "|":
                    $result = $composite->nodes[0] || $composite->nodes[1];
                    break;
                default:
                    $result = false;
            }
        }

        if ($composite->isNegated()) {
            return !$result;
        }
        return $result;
    }