Skip to content

Latest commit

 

History

History
183 lines (148 loc) · 7.21 KB

File metadata and controls

183 lines (148 loc) · 7.21 KB

Developer Documentation

Welcome to the Developer Documentation for the GitHub User Viewer. This document explains the architecture of the application, how classes are connected, the design patterns utilized, and the data flows between the components.


🏗️ Architectural Overview

The application is structured around the Single Responsibility Principle (SRP) and the Strategy Pattern to handle different HTTP request methods. Concerns are cleanly separated into Models, Clients, Fetchers, Exporters, and Utilities.

classDiagram
    direction TB
    class ProfileFetcherInterface {
        <<interface>>
        +fetch(array usernames) array
    }
    class SequentialFetcher {
        -GitHubClient client
        +fetch(array usernames) array
    }
    class ParallelFetcher {
        -GitHubClient client
        +fetch(array usernames) array
    }
    class GitHubClient {
        -string token
        +createHandle(string url) CurlHandle|false
        +createHandleForUser(string username) CurlHandle|false
        +fetchProfile(string username) UserProfile
        +parseResponse(string response, CurlHandle ch, string defaultUsername) UserProfile
    }
    class UserProfile {
        +string username
        +bool success
        +string name
        +string avatarUrl
        +string htmlUrl
        +string bio
        +string company
        +string location
        +int followers
        +int following
        +int publicRepos
        +string error
        +int|null rateLimitRemaining
        +int|null rateLimitLimit
        +fromFailure(string username, string error) UserProfile
        +toArray() array
    }
    class UsernameCleaner {
        +clean(string input) array
    }
    class CsvExporter {
        +export(array results) void
    }

    ProfileFetcherInterface <|.. SequentialFetcher
    ProfileFetcherInterface <|.. ParallelFetcher
    SequentialFetcher --> GitHubClient : depends on
    ParallelFetcher --> GitHubClient : depends on
    GitHubClient ..> UserProfile : creates
    CsvExporter ..> UserProfile : exports data from
Loading

🎨 Design Patterns & Principles

1. Strategy Pattern

We define a common ProfileFetcherInterface contract.

  • SequentialFetcher implements standard sequential queries.
  • ParallelFetcher implements parallel queries using Multi-cURL. This allows the client code in index.php to run both strategies side-by-side or swap them out without modifying the execution details of the controller.

2. Data Transfer Object (DTO)

The UserProfile class encapsulates the structured profile response from the GitHub API. Rather than passing raw associative arrays containing unchecked keys, the application maps raw JSON to a strongly-typed UserProfile class representation.

3. Dependency Injection (DI)

The client (GitHubClient) is injected into the fetchers via their constructors. This decouples the network-calling mechanism from the orchestration of multiple requests, making components modular and testable.


🗂️ Core Class Connections

App\Client\GitHubClient

  • Configures cURL handles with GitHub headers, agent parameters, and rate-limiting authorization tokens.
  • Extracts HTTP response headers (e.g. rate limit states) and decodes bodies.
  • Handles API errors gracefully (e.g. mapping 404 to "User not found", 403 to "Rate limit exceeded").

App\Model\UserProfile

  • Stores specific user profile data.
  • Exposes toArray() to support the front controller and keep compatibility with the client-side JavaScript (script.js).

App\Util\UsernameCleaner

  • Takes raw text input from the user (from commas, newlines, tabs, spaces), sanitizes it, and runs a case-insensitive de-duplication loop.

App\Exporter\CsvExporter

  • Iterates through profile records and outputs headers to immediately trigger file streams (php://output) to prompt a user download.

🔄 Core Web Workflows

1. The Main Search & Benchmark Flow

When a user submits a list of developer usernames, the following pipeline executes:

sequenceDiagram
    autonumber
    actor User as User Browser
    participant Index as index.php
    participant Cleaner as UsernameCleaner
    participant Client as GitHubClient
    participant Seq as SequentialFetcher
    participant Parallel as ParallelFetcher

    User->>Index: POST: usernames & token
    Index->>Cleaner: clean(usernamesInput)
    Cleaner-->>Index: array of clean usernames
    Index->>Client: __construct(githubToken)
    Index->>Seq: __construct(client)
    Index->>Seq: fetch(cleanUsernames)
    loop For each username
        Seq->>Client: fetchProfile(username)
        Client-->>Seq: UserProfile instance
    end
    Seq-->>Index: Sequential results & duration

    Index->>Parallel: __construct(client)
    Index->>Parallel: fetch(cleanUsernames)
    Parallel->>Client: createHandleForUser(username) for all profiles
    Parallel->>Parallel: curl_multi_exec() loops
    Parallel->>Client: parseResponse() for all handles
    Client-->>Parallel: UserProfile instances
    Parallel-->>Index: Parallel results & duration

    Index-->>User: Render comparative HTML and graphs
Loading

2. AJAX Repositories Request Flow

  • When the user clicks the folder icon (📂) next to a developer in the directory:
    1. Javascript (script.js) intercepts the click and makes a fetch request to index.php?action=repos&username={username}.
    2. index.php instantiates GitHubClient and obtains a cURL handle for https://api.github.com/users/{username}/repos?per_page=30.
    3. The proxy request executes, extracts the body payload, and prints it back to the client as JSON.
    4. Javascript renders the repository list inside a modal overlay.

🛠️ Verification & Testing Guidelines

This codebase uses automated tools to maintain code quality, security, and standards.

1. Code Style Enforcement

The codebase adheres to the PSR-12 Extended Coding Style Guide. Coding standard compliance is enforced in the CI/CD pipeline using PHP_CodeSniffer.

To run the style checker locally:

composer lint

To automatically format style violations using PHPCBF:

vendor/bin/phpcbf --standard=PSR12 src/ tests/

2. Automated Test Suite

Unit and integration tests are written using PHPUnit and are located in the /tests directory.

To run the full test suite locally:

composer test

3. Isolated Mock Testing (Networkless execution)

To test the API client logic without hitting the live GitHub API rate limits, we use namespace-level function overriding.

  • Inside the test files, we override PHP's native cURL functions (e.g., curl_errno, curl_getinfo, curl_multi_exec, curl_multi_getcontent) within the App\Client and App\Fetcher namespaces.
  • This intercepts calls when PHP resolves the functions, returning mocked response headers, status codes (such as 200, 403, 404), and error numbers (like timeouts).
  • This ensures test execution is extremely fast (~20ms) and works perfectly without an active internet connection.

4. Performance Analysis

Make sure the Parallel Speedup metric remains accurate. Parallel cURL requests should run in a time frame close to: $$\text{Total Time} \approx \text{Response time of the slowest single API request} + \text{Multi-cURL overhead}$$