Trongate PHP Framework Docs
Introduction
Quick Start
Basic Concepts
Understanding Routing
Intercepting Requests
Module Fundamentals
Database Operations
Templates
Helpers
Form Handling
Form Validation
Working With Files
Image Manipulation
Working With Dates & Times
Language Control
Security
Tips And Best Practices

Week Input Fields

The week input field allows users to select a week and year. It provides a user-friendly week picker and submits data in YYYY-W## format using ISO 8601 week numbering.

Browser Display vs Submitted Format: Browsers display weeks according to user locale, but always submit in consistent ISO 8601 format (YYYY-W##) that your PHP code can rely on.

Basic Usage

Use to create a week input field:

PHP
echo form_week('work_week');
// Output: <input type="week" name="work_week">

Demonstration

Below is the native HTML5 week input rendered by form_week():

Function Signature

PHP
function form_week(string $name, ?string $value = null, array $attributes = []): string

Parameters

Parameter Type Description Default
$name string The name attribute for the input (required) N/A
$value string|null The value in YYYY-W## format null
$attributes array Additional HTML attributes []

With a Default Value

PHP
echo form_week('timesheet_week', '2025-W52');
// Output: <input type="week" name="timesheet_week" value="2025-W52">

Setting Current Week as Default

PHP
$current_week = date('Y') . '-W' . str_pad(date('W'), 2, '0', STR_PAD_LEFT);
echo form_week('reporting_week', $current_week);

Zero-Padding Required: Week numbers must be zero-padded: W01 not W1. Always use str_pad(date('W'), 2, '0', STR_PAD_LEFT) to ensure proper formatting.

With Attributes

PHP
$attributes = [
    'min' => '2025-W01',
    'max' => '2025-W52',
    'required' => true
];
echo form_week('schedule_week', '', $attributes);

Output:

HTML
<input type="week" name="schedule_week" value="" min="2025-W01" max="2025-W52" required>

Boolean Attributes: Pass true for boolean attributes like required, readonly, or disabled. This generates clean HTML5 syntax: <input required>

Downloadable Demo: Want to see the function in action? Why not head over to GitHub and check out the complete Weekly Schedules demo module:

https://github.com/trongate/Trongate-v2-Weekly-Schedules-Module

This repository provides a ready-to-use example of building a weekly scheduling system using the Trongate PHP framework (version 2). It includes pagination, form validation, secure admin access, native HTML5 week input handling, and clean separation of concerns.

Common Attributes

Attribute Purpose Example
min Earliest selectable week (YYYY-W##) ['min' => '2025-W01']
max Latest selectable week (YYYY-W##) ['max' => '2025-W52']
required Field must have a value ['required' => true]
readonly Prevent user editing ['readonly' => true]
disabled Disable the input ['disabled' => true]

Understanding ISO 8601 Week Numbering

Week inputs follow the ISO 8601 international standard for week numbering. Understanding these rules is important:

ISO 8601 Week Rules:

  • Weeks start on Monday (not Sunday)
  • Week 1 is the first week that contains a Thursday in the new year
  • This means January 1st might be in week 52 or 53 of the previous year
  • A year can have 52 or 53 weeks

Example of Week 1 Determination

PHP
// If January 1, 2025 is a Wednesday:
// - It contains a Thursday (Jan 2) in the same week
// - Therefore: January 1, 2025 is in Week 1 of 2025 (2025-W01)

// If January 1, 2026 is a Thursday:
// - It IS the Thursday of that week
// - Therefore: January 1, 2026 is in Week 1 of 2026 (2026-W01)

// If January 1, 2027 is a Friday:
// - The Thursday of that week is December 31, 2026
// - Therefore: January 1, 2027 is in Week 53 of 2026 (2026-W53)

How to Repopulate Forms After Validation Errors

Controller Example

PHP
public function create(): void {
    // Fetch posted value (returns empty string if form hasn't been submitted)
    $data['work_week'] = post('work_week', true);
    $data['schedule_week'] = post('schedule_week', true);
    
    // Pass data to view
    $this->view('timesheet_form', $data);
}

View Example

PHP
<?php
echo form_open('timesheets/submit');
echo form_label('Work Week');
echo form_week('work_week', $work_week);
echo form_label('Schedule Week');
echo form_week('schedule_week', $schedule_week);
echo form_submit('submit', 'Save');
echo form_close();
?>

Form Repopulation Pattern: Always use post('field_name', true) in the controller to fetch submitted values. The true parameter trims whitespace, ensuring clean data.

Real-World Example: Weekly Timesheet

Controller:

PHP
public function timesheet(): void {
    $data['headline'] = 'Submit Timesheet';
    $data['work_week'] = post('work_week', true);
    
    // Default to current week if not submitted
    if ($data['work_week'] === '') {
        $data['work_week'] = date('Y') . '-W' . str_pad(date('W'), 2, '0', STR_PAD_LEFT);
    }
    
    $data['form_location'] = BASE_URL . 'timesheets/submit';
    $this->templates->admin($data);
}

public function submit(): void {
    $this->validation->set_rules('work_week', 'work week', 'required|valid_week');
    $this->validation->set_rules('hours_worked', 'hours worked', 'required|numeric|greater_than[0]');

    if ($this->validation->run() === true) {
        $data['work_week'] = post('work_week', true);
        $data['hours_worked'] = post('hours_worked', true);
        $data['user_id'] = $_SESSION['user_id'];
        
        $this->db->insert($data, 'timesheets');
        
        set_flashdata('Timesheet submitted successfully');
        redirect('timesheets/manage');
    } else {
        $this->timesheet();
    }
}

View:

PHP
<h1><?= $headline ?></h1>
<?= validation_errors() ?>

<?php
echo form_open($form_location);

echo form_label('Work Week');
$current = date('Y') . '-W' . str_pad(date('W'), 2, '0', STR_PAD_LEFT);
$week_attrs = [
    'max' => $current, // Can't submit future timesheets
    'required' => true
];
echo form_week('work_week', $work_week, $week_attrs);

echo form_label('Hours Worked');
echo form_number('hours_worked', $hours_worked, ['required' => true, 'step' => 0.5, 'min' => 0]);

echo form_submit('submit', 'Submit Timesheet');
echo form_close();
?>

Working with the Create/Update Pattern

PHP
public function create(): void {
    $update_id = segment(3, 'int');
    
    if ($update_id > 0 && REQUEST_TYPE === 'GET') {
        // Editing existing record - load from database
        $record = $this->db->get_where($update_id, 'schedules');
        $data['task_name'] = $record->task_name;
        $data['schedule_week'] = $record->schedule_week; // Already in YYYY-W## format
    } else {
        // New record OR validation error - use POST data
        $data['task_name'] = post('task_name', true);
        $data['schedule_week'] = post('schedule_week', true);
    }
    
    $data['form_location'] = BASE_URL . 'schedules/submit/' . $update_id;
    $this->view('schedule_form', $data);
}

Type-Casting Segments: Always use segment(3, 'int') when expecting numeric IDs. This prevents type-related bugs and improves code clarity.

Database Storage

Week inputs submit in YYYY-W## format, which can be stored directly in a VARCHAR column:

Table Schema

SQL
CREATE TABLE timesheets (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT,
    work_week VARCHAR(8), -- Stores YYYY-W##
    hours_worked DECIMAL(5, 2),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Inserting Data

PHP
public function submit(): void {
    $this->validation->set_rules('work_week', 'work week', 'required|valid_week');
    
    if ($this->validation->run() === true) {
        $data['user_id'] = $_SESSION['user_id'];
        $data['work_week'] = post('work_week', true); // e.g., "2025-W52"
        $data['hours_worked'] = post('hours_worked', true);
        
        $this->db->insert($data, 'timesheets');
        redirect('timesheets/manage');
    } else {
        $this->create();
    }
}

Direct Storage: The YYYY-W## format from HTML5 week inputs can be stored directly in a VARCHAR(8) column. No conversion is needed, and the data remains human-readable.

Converting Week to Date Range

To query data for a specific week, you'll often need to convert to a date range:

PHP
// Input: 2025-W52
$week = post('work_week', true);

// Parse week
$date = new DateTime();
$date->setISODate(
    (int) substr($week, 0, 4),  // Year: 2025
    (int) substr($week, 6)       // Week number: 52
);

// Get Monday of that week
$monday = $date->format('Y-m-d');

// Get Sunday of that week
$date->modify('+6 days');
$sunday = $date->format('Y-m-d');

echo "Week $week runs from $monday to $sunday";
// Output: Week 2025-W52 runs from 2025-12-22 to 2025-12-28

Querying by Week

Query by Stored Week Value

PHP
// Simplest approach: query by stored week value
$week = '2025-W52';

$sql = "SELECT * FROM timesheets 
        WHERE work_week = :week
        ORDER BY created_at";

$results = $this->db->query_bind($sql, ['week' => $week], 'array');

Query by Date Range

PHP
// Calculate date range for a week
$week = '2025-W52';
list($year, $week_num) = explode('-W', $week);

$date = new DateTime();
$date->setISODate((int) $year, (int) $week_num);
$start_date = $date->format('Y-m-d');
$date->modify('+6 days');
$end_date = $date->format('Y-m-d');

$sql = "SELECT * FROM activities 
        WHERE activity_date BETWEEN :start AND :end
        ORDER BY activity_date";

$results = $this->db->query_bind($sql, [
    'start' => $start_date,
    'end' => $end_date
], 'array');

Formatting Weeks for Display

When displaying weeks to users, you'll often want to format them in a more readable way:

PHP
// Input: 2025-W52

// Extract year and week number
preg_match('/(\d{4})-W(\d{2})/', '2025-W52', $matches);
$year = $matches[1];
$week_num = $matches[2];

echo "Week $week_num of $year";      // Week 52 of 2025
echo "Week $week_num, $year";        // Week 52, 2025

// Get date range for display
$date = new DateTime();
$date->setISODate((int) $year, (int) $week_num);
$start = $date->format('M j');
$date->modify('+6 days');
$end = $date->format('M j, Y');

echo "$start - $end"; // Dec 22 - Dec 28, 2025

// More detailed format
$date->setISODate((int) $year, (int) $week_num);
$monday = $date->format('l, F j');
$date->modify('+6 days');
$sunday = $date->format('l, F j, Y');

echo "$monday through $sunday";
// Monday, December 22 through Sunday, December 28, 2025

Validation

Use the valid_week validation rule to ensure the submitted value is in the correct format:

PHP
$this->validation->set_rules('work_week', 'work week', 'required|valid_week');

This validates that the value matches YYYY-W## format and represents a valid week.

Client vs Server Validation: While browsers validate week formats client-side, always use server-side validation with valid_week. Client validation can be bypassed and doesn't protect your database.

See the Validating Date and Time Data chapter for complete validation rule documentation.

Restricting Week Selection

Current Year Only

PHP
$current_year = date('Y');
$attributes = [
    'min' => $current_year . '-W01',
    'max' => $current_year . '-W52',
    'required' => true
];
echo form_week('report_week', $report_week, $attributes);

Past 4 Weeks

PHP
$current_week = (int) date('W');
$current_year = date('Y');

$max_week = date('Y') . '-W' . str_pad($current_week, 2, '0', STR_PAD_LEFT);
$min_week = date('Y') . '-W' . str_pad(max(1, $current_week - 4), 2, '0', STR_PAD_LEFT);

$attributes = [
    'min' => $min_week,
    'max' => $max_week,
    'required' => true
];
echo form_week('timesheet_week', $timesheet_week, $attributes);

Specific Week Range

PHP
$attributes = [
    'min' => '2025-W10',
    'max' => '2025-W20',
    'required' => true
];
echo form_week('project_week', $project_week, $attributes);

Common Use Cases

  • Timesheets - Weekly hour tracking and time entry
  • Production planning - Weekly manufacturing schedules and capacity planning
  • Sales targets - Weekly sales goals, quotas, and performance tracking
  • Project management - Sprint planning (typically 1-2 week sprints)
  • Staff scheduling - Weekly work rosters and shift planning
  • Delivery schedules - Weekly shipping plans and logistics
  • Weekly reports - Status reports, KPIs, and performance metrics
  • Appointment scheduling - Weekly availability and booking slots

Browser Support and Rendering

Different browsers provide different week picker interfaces:

  • Chrome/Edge: Calendar view with week numbers highlighted
  • Firefox: Week and year input fields with increment/decrement controls
  • Safari: Limited support - may render as text input
  • Mobile (iOS/Android): Native week picker where supported

Safari Limitation: Week input support is limited in Safari. It may render as a plain text input. Users can still manually enter values in YYYY-W## format (e.g., "2025-W52"), and validation will work correctly. Consider adding helper text for Safari users.

Providing Helper Text

PHP
echo form_label('Work Week');
echo form_week('work_week', $work_week, ['required' => true]);
echo '<small class="help-text">Format: YYYY-W## (e.g., 2025-W52)</small>';

Important Notes

  • Value format is always YYYY-W## with zero-padded week number
  • Store as VARCHAR(8) in database
  • No conversion needed between form and database
  • Week numbers follow ISO 8601 standard (weeks start Monday)
  • Always use str_pad() for week numbers to ensure zero-padding
  • January 1st may be in week 52 or 53 of the previous year
  • Safari support is limited - may fallback to text input
  • Browser validates format automatically, but server validation is still required

Value Format: The value attribute must be in YYYY-W## format with zero-padded week numbers. Values like 2025-W5 (missing zero) or 2025/W52 (wrong separator) will not work and the field will appear empty.

We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.

Share your thoughts in the Documentation Feedback.

Leave Feedback About This Page