Overview
The Submission model represents a single code submission by a user to a problem in an assignment. It stores the submission metadata, judging results, and final score calculations.
Traits
use Prunable, HasFactory;
- Prunable: Automatically removes submissions for deleted users
- HasFactory: Enables factory pattern for testing
Fillable Fields
Unique identifier for the submission
ID of the user who made the submission
ID of the assignment (0 for practice submissions)
ID of the problem being solved
Whether this submission is counted for final scoringOnly one submission per user-problem pair should have is_final = 1
Execution time in seconds (maximum across all test cases)
Submission status: ‘Pending’, ‘Judging’, ‘Done’, ‘Failed’
Raw score before applying coefficient (0-10000, where 10000 = 100%)Calculated based on test cases passed
Late submission penalty coefficient (0-100) or “error” if calculation failedFinal score = (pre_score * problem_score / 10000) * (coefficient / 100)
Name of the submitted source code file
ID of the programming language used
Detailed judging results parsed from result HTMLCast: objectStructure:{
"times": [0.01, 0.02, 0.01],
"mems": [1024, 1536, 1280],
"verdicts": {
"Correct": 3,
"Wrong Answer": 1
}
}
Casts
protected $casts = [
'judgement' => 'object'
];
Relationships
user()
The user who made this submission
$submission->user // Returns User model
assignment()
The assignment this submission belongs to
$submission->assignment // Returns Assignment model
problem()
$submission->problem // Returns Problem model
language()
The programming language used for this submission
$submission->language // Returns Language model
Public Methods
get_path()
Static method to get the filesystem path for a user’s submissions.
public static function get_path($username, $assignment_id, $problem_id)
Parameters:
$username (string) - Username
$assignment_id (integer) - Assignment ID
$problem_id (integer) - Problem ID
Returns: string - Absolute path to submission directory
Example:
$path = Submission::get_path('john_doe', 5, 10);
// Returns: '/var/www/assignments/assignment_5/problem_10/john_doe'
get_relative_path()
Static method to get the relative path for a user’s submissions.
public static function get_relative_path($username, $assignment_id, $problem_id)
Parameters:
$username (string) - Username
$assignment_id (integer) - Assignment ID
$problem_id (integer) - Problem ID
Returns: string - Relative path from assignments root
Example:
$path = Submission::get_relative_path('john_doe', 5, 10);
// Returns: '/assignment_5/problem_10/john_doe'
directory()
Gets the filesystem directory for this submission.
public function directory()
Returns: string - Absolute path to submission directory
Example:
$dir = $submission->directory();
// Returns: '/var/www/assignments/assignment_5/problem_10/john_doe'
Directory contents:
assignment_{id}/problem_{id}/{username}/
├── {file_name} # Submitted source code
├── result-{submission_id}.html # Judging results
├── compile-{submission_id}.txt # Compilation output
└── exec/ # Execution files (temporary)
get_judgement_from_result_html()
Parses the result HTML file to extract judging details.
public function get_judgement_from_result_html()
Returns: array with keys:
times (array) - Execution time for each test case (seconds)
mems (array) - Memory usage for each test case (KiB)
verdicts (array) - Count of each verdict type
Example:
$judgement = $submission->get_judgement_from_result_html();
print_r($judgement);
// Output:
// [
// 'times' => [0.01, 0.02, 0.015, 0.012],
// 'mems' => [1024, 1536, 1280, 1152],
// 'verdicts' => [
// 'Correct' => 3,
// 'Wrong Answer' => 1
// ]
// ]
Verdict types:
Correct - Output matches expected
Wrong Answer - Output doesn’t match
Time Limit Exceeded - Execution took too long
Runtime Error - Program crashed
Compilation Error - Code didn’t compile
Memory Limit Exceeded - Used too much memory
get_final_submissions()
Static method to retrieve final submissions for an assignment.
public static function get_final_submissions($assignment_id)
Parameters:
$assignment_id (integer) - Assignment ID
Returns: Collection - Submissions with user information
Access control:
- Admin/instructors: See all final submissions
- Students: See only their own final submissions
Example:
$finals = Submission::get_final_submissions(5);
foreach ($finals as $sub) {
echo "{$sub->username}: Problem {$sub->problem_id} - Score {$sub->pre_score}\n";
}
Columns returned:
- All
submissions table columns
username from joined users table
Ordering:
- First by
username (ascending)
- Then by
problem_id (ascending)
prunable()
Defines the query for pruning orphaned submissions.
public function prunable()
Returns: Builder - Query for submissions without associated users
Usage:
// Run automatically or via command
php artisan model:prune
Scoring Calculation
Submission scores are calculated in multiple steps:
1. Pre-Score (0-10000)
// Based on test cases passed
$pre_score = (passed_tests / total_tests) * 10000;
2. Problem Score
// Get problem's score from assignment pivot
$problem_score = $assignment->problems()->find($problem_id)->pivot->score;
// Calculate points earned
$points = ceil(($pre_score * $problem_score) / 10000);
3. Apply Coefficient (Late Penalty)
if ($submission->coefficient === 'error') {
$final_score = 0;
} else {
$final_score = ceil($points * ($submission->coefficient / 100));
}
Example
// Submission passed 8 out of 10 test cases
$pre_score = 8000; // (8/10) * 10000
// Problem worth 100 points in assignment
$problem_score = 100;
$points = ceil((8000 * 100) / 10000); // 80 points
// Submitted 1 hour late, coefficient = 80%
$coefficient = 80;
$final_score = ceil(80 * (80 / 100)); // 64 points
File Structure
Each submission creates files in the filesystem:
# Submission directory
/var/www/assignments/assignment_5/problem_10/john_doe/
# Files created:
submission_123.cpp # Source code
result-123.html # Formatted judge results
compile-123.txt # Compiler output
exec-123 # Compiled executable (temp)
Example Usage
// Create a submission
$submission = Submission::create([
'user_id' => auth()->id(),
'assignment_id' => 5,
'problem_id' => 10,
'is_final' => 0,
'status' => 'Pending',
'pre_score' => 0,
'coefficient' => $assignment->eval_coefficient(),
'file_name' => 'solution.cpp',
'language_id' => 1,
]);
// After judging, update results
$judgement = $submission->get_judgement_from_result_html();
$submission->update([
'status' => 'Done',
'pre_score' => 8500, // 85% test cases passed
'judgement' => $judgement,
'time' => max($judgement['times']),
]);
// Get final submissions for scoreboard
$finals = Submission::get_final_submissions($assignmentId);
// Check if this is the best submission
$assignment->reset_final_submission_choices();
// Access submission details
echo "User: {$submission->user->username}\n";
echo "Problem: {$submission->problem->name}\n";
echo "Language: {$submission->language->name}\n";
echo "Score: {$submission->pre_score}/10000\n";
echo "Coefficient: {$submission->coefficient}%\n";
if ($submission->judgement) {
echo "Verdicts: " . json_encode($submission->judgement->verdicts);
}
Status Workflow
- Pending: Submission created, waiting in queue
- Judging: Being evaluated against test cases
- Done: All test cases evaluated, results available
- Failed: System error during judging (e.g., timeout, disk full)