> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/appertafoundation/openeyes/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> Understanding OpenEyes technical architecture and design patterns

OpenEyes is built on a modular, event-based architecture using the Yii 1.x PHP framework. This page covers the technical architecture and core design patterns.

## Technology Stack

### Core Framework

OpenEyes is built on **Yii Framework 1.1.28**, a high-performance PHP framework based on the Model-View-Controller (MVC) pattern.

```json protected/composer.json theme={null}
{
  "require": {
    "php": "^7.4 || ^8.0 || ^8.1",
    "yiisoft/yii": "1.1.28"
  }
}
```

### Dependencies

Key dependencies include:

* **PHP 7.4+** with support for PHP 8.0 and 8.1
* **MySQL/MariaDB** for data storage
* **PHPUnit 9.6.5** for testing
* **Faker** for test data generation
* **PHPStan** for static analysis

## Architecture Overview

### MVC Pattern

OpenEyes follows the classic Model-View-Controller pattern:

```
protected/
├── models/          # Data models and business logic
├── controllers/     # Request handling and flow control
├── views/          # Presentation layer
├── components/     # Reusable components
└── modules/        # Event type modules
```

### Core Models

The system is built around several key models:

#### Patient Model

The Patient model is central to the system:

```php protected/models/Patient.php theme={null}
class Patient extends BaseActiveRecordVersioned
{
    use HasFactory;

    const CHILD_AGE_LIMIT = 16;
    const PATIENT_SOURCE_OTHER = 0;
    const PATIENT_SOURCE_REFERRAL = 1;
    const PATIENT_SOURCE_SELF_REGISTER = 2;

    // Properties
    // @property int $id
    // @property string $first_name
    // @property string $last_name
    // @property string $dob
    // @property string $gender
    // @property string $hos_num
    // @property string $nhs_num

    // Relations
    // @property Episode[] $episodes
    // @property Address[] $addresses
    // @property Contact $contact
    // @property Gp $gp
    // @property Practice $practice
    // @property Allergy[] $allergies
}
```

#### Event Model

Events represent clinical encounters:

```php protected/models/Event.php theme={null}
class Event extends BaseActiveRecordVersioned
{
    use HasFactory;

    // Properties
    // @property string $id
    // @property string|int $episode_id
    // @property string|int $user_id
    // @property string|int $event_type_id
    // @property boolean $deleted
    // @property string $event_date

    // Relations
    // @property Episode $episode
    // @property User $user
    // @property EventType $eventType
    // @property EventIssue[] $issues
}
```

## Event-Based Architecture

### BaseEventTypeController

All event modules extend `BaseEventTypeController`, which provides standardized CRUD operations:

```php protected/controllers/BaseEventTypeController.php theme={null}
class BaseEventTypeController extends BaseModuleController
{
    const ACTION_TYPE_CREATE = 'Create';
    const ACTION_TYPE_VIEW = 'View';
    const ACTION_TYPE_PRINT = 'Print';
    const ACTION_TYPE_EDIT = 'Edit';
    const ACTION_TYPE_DELETE = 'Delete';

    public $patient;
    public $site;
    public ?Event $event = null;
    public $episode;
    public $editable = true;
    protected $open_elements;
}
```

The controller is stateful and provides hooks for customization:

* `setElementDefaultOptions()` - Set defaults on elements
* `setElementComplexAttributesFromData()` - Set complex attributes
* `saveElementComplexAttributesFromData()` - Save complex data

### Event Type Modules

Each clinical event type is implemented as a module. Example from OphCiExamination:

```php protected/modules/OphCiExamination/OphCiExaminationModule.php theme={null}
namespace OEModule\OphCiExamination;

class OphCiExaminationModule extends \BaseEventTypeModule
{
    public $controllerNamespace = '\OEModule\OphCiExamination\controllers';

    public function init()
    {
        $this->setImport(array(
            'application.modules.OphDrPrescription.models.*',
        ));
        $this->setModules(['ExaminationAdmin']);
        parent::init();
    }
}
```

## Module System

OpenEyes uses a modular architecture where functionality is organized into modules:

### Module Structure

```
protected/modules/OphCiExamination/
├── OphCiExaminationModule.php    # Module definition
├── controllers/
│   └── DefaultController.php     # Main controller
├── models/                       # Domain models
├── views/                        # View templates
├── migrations/                   # Database migrations
├── components/                   # Module components
├── factories/                    # Test factories
└── tests/                        # Module tests
```

### Module Naming Conventions

Modules follow specific prefixes based on type:

* **OphCi** - Clinical Investigation (e.g., OphCiExamination)
* **OphDr** - Drug/Prescription (e.g., OphDrPrescription)
* **OphTr** - Treatment (e.g., OphTrOperationnote)
* **OphCo** - Correspondence/Communication (e.g., OphCoCorrespondence)

## Database Architecture

### Migrations

Database schema changes are managed through migrations:

```
protected/migrations/
├── m130913_000000_consolidation.php
├── m131009_083758_record_no_allergies.php
└── m131015_125648_proc_aliases.php
```

Each module can have its own migrations:

```
protected/modules/OphCiExamination/migrations/
```

### Versioned Models

Core models extend `BaseActiveRecordVersioned` to track changes:

```php theme={null}
class Patient extends BaseActiveRecordVersioned
{
    // Automatic versioning of all changes
}
```

## Autoloading

Composer autoloading is configured for modern PHP namespaces:

```json composer.json theme={null}
{
  "autoload": {
    "psr-4": {
      "OE\\concerns\\": "protected/concerns",
      "OE\\contracts\\": "protected/contracts",
      "OE\\factories\\": "protected/factories",
      "OE\\listeners\\": "protected/listeners",
      "OE\\seeders\\": "protected/seeders"
    }
  }
}
```

## Component Architecture

### Behaviors

Yii behaviors provide reusable functionality:

```
protected/behaviors/
```

### Widgets

Reusable UI components:

```
protected/widgets/
```

### Helpers

Utility functions and helper classes:

```
protected/helpers/
```

## Configuration

### Main Configuration

Configuration is loaded through `OEConfig`:

```php protected/config/main.php theme={null}
require_once dirname(__FILE__).'/OEConfig.php';
return OEConfig::getMergedConfig('main');
```

Local overrides can be placed in:

```
protected/config/local/
```

## Event System

OpenEyes uses Yii's event system for extensibility:

* Event listeners in `protected/listeners/`
* Components can raise and listen for events
* Modules can hook into application-wide events

## Services Layer

Business logic is organized into services:

```
protected/services/
```

## Security

### Access Control

Access control is managed through:

* Role-based access control (RBAC)
* Controller-level access rules
* Action-type based permissions

### Data Validation

All models implement validation rules:

```php theme={null}
public function rules()
{
    return [
        ['first_name, last_name', 'required'],
        ['email', 'email'],
    ];
}
```

## Performance Considerations

### Caching

Yii provides caching mechanisms:

* Database query caching
* Fragment caching
* Full page caching

### Asset Management

Assets are organized per module:

```
protected/modules/OphCiExamination/assets/
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Module Development" icon="puzzle-piece" href="/development/modules">
    Learn how to create custom modules
  </Card>

  <Card title="Testing" icon="vial" href="/development/testing">
    Understanding the testing approach
  </Card>
</CardGroup>
