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

Month Input Fields

The month input field allows users to select a month and year. It provides a user-friendly month picker and submits data in YYYY-MM format.

Browser Display vs Submitted Format: Browsers display months according to user locale, but always submit in consistent YYYY-MM format that your PHP code can rely on.

Basic Usage

Use to create a month input field:

PHP
echo form_month('billing_month');
// Output: <input type="month" name="billing_month">

Demonstration

Below is the native HTML5 month input rendered by form_month():

Function Signature

PHP
function form_month(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-MM format null
$attributes array Additional HTML attributes []

With a Default Value

PHP
echo form_month('report_month', '2025-12');
// Output: <input type="month" name="report_month" value="2025-12">

Setting Current Month as Default

PHP
$current_month = date('Y-m');
echo form_month('subscription_month', $current_month);

Automatic Zero-Padding: PHP's date('Y-m') automatically zero-pads the month, producing values like 2025-01 for January.

With Attributes

PHP
$attributes = [
    'min' => '2025-01',
    'max' => '2025-12',
    'required' => true
];
echo form_month('target_month', '', $attributes);

Output:

HTML
<input type="month" name="target_month" value="" min="2025-01" max="2025-12" 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? We've made a working demo that you can download. Check out the complete Monthly Reports demo module example on GitHub:

https://github.com/trongate/Trongate-v2-Monthly-Reports-Module

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

Common Attributes

Attribute Purpose Example
min Earliest selectable month (YYYY-MM) ['min' => '2025-01']
max Latest selectable month (YYYY-MM) ['max' => '2025-12']
required Field must have a value ['required' => true]
readonly Prevent user editing ['readonly' => true]
disabled Disable the input ['disabled' => true]

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['billing_month'] = post('billing_month', true);
    $data['report_month'] = post('report_month', true);
    
    // Pass data to view
    $this->view('billing_form', $data);
}

View Example

PHP
<?php
echo form_open('billing/submit');
echo form_label('Billing Month');
echo form_month('billing_month', $billing_month);
echo form_label('Report Month');
echo form_month('report_month', $report_month);
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: Monthly Report Selection

Controller:

PHP
public function generate_report(): void {
    $data['headline'] = 'Generate Monthly Report';
    $data['report_month'] = post('report_month', true);
    
    // Default to current month if not submitted
    if ($data['report_month'] === '') {
        $data['report_month'] = date('Y-m');
    }
    
    $data['form_location'] = BASE_URL . 'reports/submit';
    $this->templates->admin($data);
}

public function submit(): void {
    $this->validation->set_rules('report_month', 'report month', 'required|valid_month');

    if ($this->validation->run() === true) {
        $report_month = post('report_month', true);
        
        // Generate report for selected month
        $report_data = $this->generate_monthly_data($report_month);
        
        set_flashdata('Report generated for ' . $report_month);
        redirect('reports/view/' . $report_month);
    } else {
        $this->generate_report();
    }
}

private function generate_monthly_data(string $month): array {
    // Parse month: 2025-12 becomes year=2025, month=12
    list($year, $month_num) = explode('-', $month);
    
    // Query data for this month
    $sql = "SELECT * FROM sales 
            WHERE YEAR(sale_date) = :year 
            AND MONTH(sale_date) = :month";
    
    return $this->db->query_bind($sql, [
        'year' => $year,
        'month' => $month_num
    ], 'array');
}

View:

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

<?php
echo form_open($form_location);

echo form_label('Report Month');
$attrs = [
    'max' => date('Y-m'), // Can't generate reports for future months
    'required' => true
];
echo form_month('report_month', $report_month, $attrs);

echo form_submit('submit', 'Generate Report');
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, 'subscriptions');
        $data['customer_name'] = $record->customer_name;
        $data['billing_month'] = $record->billing_month; // Already in YYYY-MM format
    } else {
        // New record OR validation error - use POST data
        $data['customer_name'] = post('customer_name', true);
        $data['billing_month'] = post('billing_month', true);
    }
    
    $data['form_location'] = BASE_URL . 'subscriptions/submit/' . $update_id;
    $this->view('subscription_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

Month inputs submit in YYYY-MM format, which can be stored directly in a VARCHAR column:

Table Schema

SQL
CREATE TABLE subscriptions (
    id INT PRIMARY KEY AUTO_INCREMENT,
    customer_name VARCHAR(255),
    billing_month VARCHAR(7), -- Stores YYYY-MM
    amount DECIMAL(10, 2),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Inserting Data

PHP
public function submit(): void {
    $this->validation->set_rules('billing_month', 'billing month', 'required|valid_month');
    
    if ($this->validation->run() === true) {
        $data['customer_name'] = post('customer_name', true);
        $data['billing_month'] = post('billing_month', true); // e.g., "2025-12"
        
        $this->db->insert($data, 'subscriptions');
        redirect('subscriptions/manage');
    } else {
        $this->create();
    }
}

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

Converting Month to Date Range

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

PHP
// Input: 2025-12
$month = post('billing_month', true);

// Get first and last day of the month
$first_day = $month . '-01';
$last_day = date('Y-m-t', strtotime($first_day)); // 2025-12-31

// Use in queries
$sql = "SELECT * FROM transactions 
        WHERE transaction_date BETWEEN :start AND :end
        ORDER BY transaction_date";

$data = $this->db->query_bind($sql, [
    'start' => $first_day,
    'end' => $last_day
], 'array');

Querying by Month

Using Date Functions

PHP
// Get all records for a specific month
$month = '2025-12';
list($year, $month_num) = explode('-', $month);

$sql = "SELECT * FROM sales 
        WHERE YEAR(sale_date) = :year 
        AND MONTH(sale_date) = :month
        ORDER BY sale_date";

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

Using Date Range

PHP
$month = '2025-12';
$first_day = $month . '-01';
$last_day = date('Y-m-t', strtotime($first_day));

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

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

Formatting Months for Display

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

PHP
// From database or form: 2025-12

// Simple PHP approach
$date = new DateTime('2025-12-01');
echo $date->format('F Y');  // December 2025
echo $date->format('M Y');   // Dec 2025
echo $date->format('m/Y');   // 12/2025

// Locale-aware formatting (requires intl extension)
$date = new DateTime('2025-12-01');
$formatter = new IntlDateFormatter(
    'en_US',
    IntlDateFormatter::LONG,
    IntlDateFormatter::NONE,
    null,
    null,
    'MMMM yyyy'
);
echo $formatter->format($date); // December 2025

// For French users
$formatter = new IntlDateFormatter(
    'fr_FR',
    IntlDateFormatter::LONG,
    IntlDateFormatter::NONE,
    null,
    null,
    'MMMM yyyy'
);
echo $formatter->format($date); // décembre 2025

Validation

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

PHP
$this->validation->set_rules('billing_month', 'billing month', 'required|valid_month');

This validates that the value matches YYYY-MM format and represents a valid month.

Client vs Server Validation: While browsers validate month formats client-side, always use server-side validation with valid_month. 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 Month Selection

Current Year Only

PHP
$current_year = date('Y');
$attributes = [
    'min' => $current_year . '-01',
    'max' => $current_year . '-12',
    'required' => true
];
echo form_month('report_month', $report_month, $attributes);

Last 12 Months

PHP
$max = date('Y-m');
$min = date('Y-m', strtotime('-12 months'));
$attributes = [
    'min' => $min,
    'max' => $max,
    'required' => true
];
echo form_month('period', $period, $attributes);

Future Months (Budget Planning)

PHP
$current_date = new DateTime();
$min_month = $current_date->format('Y-m');

$max_date = clone $current_date;
$max_date->modify('+12 months');
$max_month = $max_date->format('Y-m');

$attributes = [
    'min' => $min_month,
    'max' => $max_month,
    'required' => true
];
echo form_month('budget_month', $budget_month, $attributes);

Common Use Cases

  • Billing and subscriptions - Monthly billing cycles and recurring payments
  • Financial reports - Monthly revenue reports, P&L statements, expense tracking
  • Planning and budgets - Monthly budgets, forecasts, and financial planning
  • Performance reviews - Monthly KPIs, metrics, and performance tracking
  • Content calendars - Editorial planning and content scheduling by month
  • Inventory reports - Monthly stock levels and inventory analysis
  • Sales tracking - Monthly sales targets, quotas, and achievement
  • Employee records - Start months, anniversary months, review periods

Browser Rendering

Different browsers provide different month picker interfaces:

  • Chrome/Edge: Dropdown with month and year selectors
  • Firefox: Similar dropdown interface with clear navigation
  • Safari: Native month picker wheel optimized for the platform
  • Mobile: Native month picker optimized for touch input

Excellent Browser Support: Month inputs have excellent support across all modern browsers and mobile devices, providing a consistent user experience.

Important Notes

  • Value format is always YYYY-MM (e.g., 2025-12)
  • Store as VARCHAR(7) in database
  • No conversion needed between form and database
  • PHP's date('Y-m') automatically zero-pads months
  • Use for monthly periods, not specific dates within a month
  • Browser displays in user's locale but always submits in YYYY-MM format
  • Min/max attributes restrict the selectable month range
  • Browser validates format automatically, but server validation is still required

Value Format: The value attribute must be in YYYY-MM format. Values like 12/2025 or 2025-December 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