PHPackages                             timehunter/branchingassessment - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. timehunter/branchingassessment

ActiveLibrary

timehunter/branchingassessment
==============================

:description

08PHP

Since Mar 21Pushed 6y agoCompare

[ Source](https://github.com/RyanDaDeng/branching-assessment)[ Packagist](https://packagist.org/packages/timehunter/branchingassessment)[ RSS](/packages/timehunter-branchingassessment/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependenciesVersions (5)Used By (0)

Branching Assessment
====================

[](#branching-assessment)

[![Coverage Status](https://camo.githubusercontent.com/6d7a6230e4217d7bb2c9c83ee2dbe26c64bd60eafe868df883c561683a849585/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f5279616e446144656e672f6272616e6368696e672d6173736573736d656e742f62616467652e7376673f6272616e63683d6d617374657226736572766963653d676974687562)](https://coveralls.io/github/RyanDaDeng/branching-assessment?branch=master)[![Build](https://camo.githubusercontent.com/38f0da22346ebdcc7ba4c0e97a156b53558a172fa75e54d4765d6b6bbd7829f4/68747470733a2f2f7472617669732d63692e6f72672f5279616e446144656e672f6272616e6368696e672d6173736573736d656e742e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/RyanDaDeng/branching-assessment)[![StyleCI](https://camo.githubusercontent.com/77bc69b80f9addcd5517fedec2a314209d505f39355278496c1049cc1c4df901/68747470733a2f2f6769746875622e7374796c6563692e696f2f7265706f732f3137363930333031362f736869656c64)](https://github.styleci.io/repos/176903016)

Description
-----------

[](#description)

The solution is written on Laravel framework.

Requirement
-----------

[](#requirement)

1. Laravel &gt;=5.5
2. PHP &gt;= 7.0

Installation
------------

[](#installation)

1. This is a Laravel composer package, you need to have a Laravel installed first.
2. Via Composer

```
$ composer require timehunter/branchingassessment
```

3. publish assessment config

```
$ php artisan vendor:publish --provider="TimeHunter\BranchingAssessment\Providers\BranchingAssessmentServiceProvider"
```

It will publish a branchingassessment.php config file under config directory, this will be used for you to simulate and play around with the package.

Usage
-----

[](#usage)

```
// client side
 $service = BranchingAssessmentFactory::createAssessmentByArray($data);

 $service->getNextQuestionId() // first time get fist question

 $service->setQuestionResponse($questionId, $isCorrect);

 // AssessmentProcessor factory
 $service = BranchingAssessmentFactory::createAssessmentByArray($data); // create service entry

 // Rule factory
 RuleFactory::process(new AssessmentProcessor($json)) // rule processor

```

Design Keywords
---------------

[](#design-keywords)

- OOP: polymorphism
- OOP: inheritance
- OOP: encapsulation
- Strategy design pattern
- Iterator design pattern
- Factory design pattern

Above design patterns might be slightly improved according to the assessment's requirement.

Commands Simulation
-------------------

[](#commands-simulation)

1. Remember to publish the config file
2. Go to branchingassessment.php config file, you can define your own assessment structure, by default, the structure follows the given diagram from the assessment.
3. Run the following command to simulate the assessment

```
$ php artisan assessment:simulate
```

or run the following command to manually play the assessment:

```
$ php artisan assessment:start
```

Suggestions
-----------

[](#suggestions)

I highly suggest you to run the two commands to play with the system first before diving into the code.

Solution
--------

[](#solution)

#### Designs

[](#designs)

The JSON sample object from the assessment example:

```
{
   "assessment_id":"1",
   "questions":[
      {
         "question_id":"A",
         "rule":{
            "type":"simple_skip_rule",
            "correct":"C",
            "incorrect":"B"
         }
      },
      {
         "question_id":"C",
         "rule":{
            "type":"simple_skip_rule",
            "correct":"E",
            "incorrect":"F"
         }
      },
      {
         "question_id":"B",
         "rule":{
            "type":"simple_skip_rule",
            "correct":"D",
            "incorrect":"D"
         }
      },
      {
         "question_id":"D",
         "rule":{
            "type":"simple_skip_rule",
            "correct":"C",
            "incorrect":"C"
         }
      },
      {
         "question_id":"E",
         "rule":{
            "type":"simple_skip_rule",
            "correct":"G",
            "incorrect":"G"
         }
      },
      {
         "question_id":"F",
         "rule":{
            "type":"simple_skip_rule",
            "correct":"H",
            "incorrect":"H"
         }
      },
      {
         "question_id":"H",
         "rule":{
            "type":"simple_skip_rule",
            "correct":"G",
            "incorrect":null
         }
      },
      {
         "question_id":"G",
         "rule":{
            "type":"simple_skip_rule",
            "correct":null,
            "incorrect":null
         }
      }
   ]
}

```

#### Rule

[](#rule)

Currently, the solution contains two different type of rules as below: (its pretty easy to add a new rule without modifying any core code.)

##### Simple Skip rule:

[](#simple-skip-rule)

```

{
....
    'question_id': 'C',
    'rule' :{
        'type' : 'simple_skip_rule',
        'correct' => 'A',
        'incorrect' => 'B'
    }
....
}

```

Explanation: If the answer is correct, it goes to A, if the answer is incorrect, it goes to B.

##### Score Check rule:

[](#score-check-rule)

```

{
....
    'question_id': 'A',
    'rule' :{
         'type' : 'score_check_rule',
          'threshold' : 2,
          'next': 'E',
          'default': 'F'
    }
....
}

```

Explanation: If the current score is 2 (include the result of question A), and the score &gt;= 2, it goes to E else goes to F.

##### Strategy Pattern - Rule Design

[](#strategy-pattern---rule-design)

The rule design follows Strategy pattern (OOP: polymorphism), which means all the core logic has been encapsulated in AssessmentProcessor, and what you do is just to create a new strategy by extending AbstractRule class (the class implements RuleInterface).

This ensures any skip/branching logic can be freely added to the logic without touching any core code.

#### Factory Pattern - Rule creations and AssessmentProcessor creations

[](#factory-pattern---rule-creations-and-assessmentprocessor-creations)

- AssessmentProcessorFactory is used to create AssessmentProcessor based on different constructor parameters.
- RuleFactory is used to create different rule strategy by passing the AssessmentProcessor class.

#### Back-end Logic

[](#back-end-logic)

1. The first step is to parse the json to be object-based model. There are three models:

- Assessment: This stores assessment details e.g. assessmentId
- Question: This stores question details.
- QuestionMap: This is a map collection which formats the raw data to be a basic hash map by using question\_id as key. (I used Laravel Collection as a helper function.)

2. The second step is to create an iterator which will iterate through the question list by calling getNextQuestionId. I implemented iterator inside of AssessmentProcessor class. The class implements the given interface and also keeps a state of current question ID.

Iterator example:

```
    $service = BranchingAssessmentFactory::createAssessmentByArray($data);
    while ($currentQuestionId = $service->getNextQuestionId()) {
        $answer = rand(1, 0) === 1;
        $service->setQuestionResponse($currentQuestionId, $answer);
    }
```

3. The third step is to check current question's rule by using RuleFactory to create a rule processor in which will return a next question ID.

Testing
-------

[](#testing)

1. use PHPUnit to cover all essential classes and cases.
2. use travis-ci for CI/CD:
3. tests file located at package tests file
4. test coverage is using coveralls:

Reflections &amp; Conclusion
----------------------------

[](#reflections--conclusion)

I think the solution is a bit overkill if you think there are too many classes for the question. In reality, the alternative solution could be fairly simple by manipulating array directly,however, it would encounter a lot of if-else statements which against SOLID principles. My solution is fully based on OOP idea and following SOLID principles as much as possible.

Note: The question is a bit abstract, in real practice, I believe there can be different type of questions and the branching logic would be far more complicated.

###  Health Score

20

—

LowBetter than 14% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/957c97ad667a07032424eb2eb70cf2db7ad705c62926c23436f9ea4e32dca5b5?d=identicon)[timehunter](/maintainers/timehunter)

---

Top Contributors

[![RyanDaDeng](https://avatars.githubusercontent.com/u/37111049?v=4)](https://github.com/RyanDaDeng "RyanDaDeng (34 commits)")

### Embed Badge

![Health badge](/badges/timehunter-branchingassessment/health.svg)

```
[![Health](https://phpackages.com/badges/timehunter-branchingassessment/health.svg)](https://phpackages.com/packages/timehunter-branchingassessment)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
