Skip to content

feat: add lab - #4

Open
quang-do-se wants to merge 1 commit into
mainfrom
lab
Open

feat: add lab#4
quang-do-se wants to merge 1 commit into
mainfrom
lab

Conversation

@quang-do-se

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR turns the repository into a self-contained “Senior Interview Lab” with two SQLite-backed PHP exercises and a lab.php CLI to set up/reset/inspect the exercise databases.

Changes:

  • Added lab.php CLI plus support utilities (Database, Schema, Args) to manage SQLite datasets.
  • Added two exercise scripts for user maintenance and order processing.
  • Updated devcontainer and README to support the new lab workflow; removed the old index.php entrypoint.

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
support/Schema.php Defines SQLite schemas for users and orders exercises.
support/Database.php Provides SQLite PDO connection helper (enables foreign keys/WAL).
support/Args.php Adds simple --key=value CLI argument parsing helpers.
README.md Replaces starter README with lab/exercise instructions.
lab.php Adds CLI commands to setup/reset/inspect SQLite datasets.
index.php Removes the previous “Hello, World!” starter entrypoint.
exercises/01_user_maintenance.php Adds the user-maintenance exercise script.
exercises/02_order_processing.php Adds the order-processing exercise script.
data/.gitkeep Keeps data/ directory present in git for SQLite files.
.gitignore Ignores generated SQLite DB/WAL/SHM files and jsonl artifacts.
.devcontainer/php-memory-limit.ini Sets PHP memory limit to 32M in the devcontainer.
.devcontainer/Dockerfile Builds a PHP devcontainer image with pdo_sqlite enabled.
.devcontainer/devcontainer.json Switches devcontainer to build from the custom Dockerfile.
Suppressed comments (1)

lab.php:46

  • The help text advertises a --fail-on option for the order-processing exercise, but the exercise script does not implement or parse that option. This will confuse users following the help output.
  php exercises/02_order_processing.php --fail-on=4

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread exercises/02_order_processing.php
Comment thread lab.php Outdated
Comment thread exercises/01_user_maintenance.php Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 1 comment.

Suppressed comments (3)

support/Database.php:12

  • mkdir() is not checked for failure; if directory creation fails (permissions, read-only FS, etc.) the code proceeds and the later PDO error will be harder to diagnose. Validate mkdir() succeeded and throw a clear exception if not.
        $dir = dirname($path);
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }

support/Args.php:29

  • If a numeric option is passed as a flag without a value (e.g. --users instead of --users=100), parse() stores true and this method will cast it to 1, which is surprising and can lead to accidental behavior. Treat boolean flags as “not provided” for int options.
    public static function int(array $args, string $key, int $default): int
    {
        return isset($args[$key]) ? (int) $args[$key] : $default;
    }

support/Args.php:34

  • Similarly, if a string option is passed as a flag without a value (e.g. --foo), parse() stores true and this method will return '1' after casting, which is confusing. Treat boolean flags as “not provided” for string options.
    public static function string(array $args, string $key, string $default): string
    {
        return isset($args[$key]) ? (string) $args[$key] : $default;
    }

Comment thread lab.php

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 1 comment.

Suppressed comments (5)

exercises/02_order_processing.php:67

  • After introducing a transaction, the success path should commit() before printing completion. Otherwise the changes may be rolled back when the script exits.
    $payment = $pdo->prepare("INSERT INTO payments(order_id, amount_cents, status) VALUES (?, ?, 'pending')");
    $payment->execute([$orderId, $total]);

    echo "Order {$orderId} completed successfully.\n";

exercises/02_order_processing.php:72

  • If an exception is thrown mid-order, the current code exits without rolling back any in-flight transaction/work. Rolling back when inTransaction() keeps the DB consistent and avoids leaving locks behind.
} catch (Throwable $e) {
    fwrite(STDERR, "FAILED: {$e->getMessage()}\n");
    fwrite(STDERR, "Inspect the DB now. Partial writes may remain.\n");
    exit(1);
}

support/Database.php:12

  • Database::connect() calls mkdir() without checking the return value. If directory creation fails (permissions, read-only FS), the subsequent PDO connection error will be harder to diagnose.

Consider failing fast with a clear exception when the directory cannot be created.

        $dir = dirname($path);
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }

exercises/01_user_maintenance.php:31

  • This script loads all eligible users into memory via fetchAll() (including profile_blob) and then performs one UPDATE per row. With the default dataset size, this can easily exceed the configured memory limit and is much slower than necessary.

You can preserve the intended behavior with a single set-based UPDATE that does not fetch user rows into PHP.

$users = $pdo->query(<<<'SQL'
    SELECT *
    FROM users
    WHERE status = 'active'
      AND last_login_at < '2025-08-13'

exercises/02_order_processing.php:15

  • $args is parsed but never used in this exercise, and the extra require_once for Args is therefore also unused. Keeping dead setup code makes the exercise harder to follow.
require_once __DIR__ . '/../support/Database.php';
require_once __DIR__ . '/../support/Args.php';

// Parse command-line options and connect to the exercise database.
$args = Args::parse($argv);

Comment thread exercises/02_order_processing.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants