v1.0.0

URL { .text-brand }

A modular core package for complete URL management, link shortening, click tracking, and privacy-safe link analytics. Designed for the Obelawium ERP framework.

Getting Started

Installation

$ composer require obelaw/ium-url

Publish Migrations

$ php artisan vendor:publish --tag=ium-url-migrations
$ php artisan migrate

Publish Config (optional)

$ php artisan vendor:publish --tag=ium-url-config

Requirements

  • PHP 8.2+
  • Laravel 11.0+ or 12.0+
  • obelaw/ium

Shorten URLs

Use the ShortenUrlData DTO to validate arguments and shorten links via the shorten service method. Returns an instance of Link.

Basic Shortening

use Obelaw\Ium\Url\Data\ShortenUrlData;

$link = ium()->url()->shorten(ShortenUrlData::from([
    'original_url' => 'https://example.com/very/long/url',
]));

// Access the shortened link
echo $link->code; // auto-generated short code
echo $link->original_url; // https://example.com/very/long/url

With Custom Code & Options

// With a custom short code, status, and expiration
$link = ium()->url()->shorten(ShortenUrlData::from([
    'original_url' => 'https://example.com/very/long/url',
    'code' => 'my-custom-code',
    'status' => 'active',
    'expires_at' => '2026-12-31 23:59:59',
]));

echo $link->code; // 'my-custom-code'
echo $link->status; // 'active'
echo $link->expires_at; // '2026-12-31 23:59:59'
PropertyTypeDescription
codestringUnique short code (custom or auto-generated)
original_urlstringThe original long URL
statusstringactive or inactive
expires_atdatetime|nullOptional link expiration timestamp
clicks_countintegerTotal click count (cached counter)

Redirect & Click Tracking

Pass visitor request details from the HTTP layer to the decoupled tracking service. The TrackUrlData DTO encapsulates IP, user agent, and referrer context.

Tracking a Click

use Obelaw\Ium\Url\Data\TrackUrlData;

// In your controller, pass request context to the service
$click = ium()->url()->track(TrackUrlData::from([
    'link_id' => $link->id,
    'ip' => $request->ip(),
    'user_agent' => $request->userAgent(),
    'referrer' => $request->header('referer'),
]));

echo $click->device_type; // 'desktop', 'mobile', etc.
echo $click->clicked_at; // timestamp of the click

Click Model Properties

PropertyDescription
ipAnonymized IP address (masked before storage)
user_agentOriginal user agent string
device_typeParsed device: desktop, mobile, tablet, robot, other
referrerHTTP referrer header value
clicked_atTimestamp of the click event

Analytics

Retrieve access aggregates, device distributions, and click referrers. The UrlStatsData DTO lets you filter results by date range and device type.

Basic Analytics Query

use Obelaw\Ium\Url\Data\UrlStatsData;

$analytics = ium()->url()->analytics(UrlStatsData::from([
    'link_id' => $link->id,
    'date_from' => '2026-01-01',
    'date_to' => '2026-05-30',
    'device_type' => null, // all devices
]));

echo $analytics->total_clicks; // 150
print_r($analytics->clicks_by_device); // array by device type
print_r($analytics->clicks_by_referrer); // array by referrer

Analytics Response Structure

KeyTypeDescription
total_clicksintegerTotal number of clicks
clicks_by_devicearrayClicks grouped by device type
clicks_by_referrerarrayClicks grouped by referrer source

Get detailed, index-friendly aggregate counts separating total link clicks from unique visitors. The stats method returns an immutable UrlStatsResultData object.

Querying Stats

$stats = ium()->url()->stats($link->id);

echo $stats->totalClicks; // 150 (all click interactions)
echo $stats->uniqueClicks; // 42 (unique visitors)
echo $stats->uniqueRatio; // 0.28 (28% unique vs total)

UrlStatsResultData Properties

PropertyTypeDescription
totalClicksintegerAll click interactions
uniqueClicksintegerUnique visitors (IP + User Agent)
uniqueRatiofloatPercentage of unique vs total clicks

How Unique Detection Works

Unique visitors are determined by aggregating distinct IP + User Agent pairs. This means the same IP from different browsers counts as multiple unique visitors, while repeat visits from the same device are counted only once.

Utilities

IP Anonymizer

The IpAnonymizer cleans visitor IP logs before storage. Both IPv4 and IPv6 addresses are masked to their network prefix, discarding the host portion.

use Obelaw\Ium\Url\Support\IpAnonymizer;

$masked = IpAnonymizer::mask('10.0.0.50');
// Result: '10.0.0.0'

$maskedV6 = IpAnonymizer::mask('2001:db8::1');
// Result: '2001:db8::'

User Agent Parser

The decoupled UserAgentParser analyzes headers to categorize visitors into device types — no heavy third-party vendor dependencies.

use Obelaw\Ium\Url\Support\UserAgentParser;

$parser = new UserAgentParser;

$parser->parse('Mozilla/5.0 (iPhone; CPU OS ...)');
echo $parser->deviceType(); // 'mobile'

$parser->parse('Mozilla/5.0 (Windows NT 10.0; ...)');
echo $parser->deviceType(); // 'desktop'
  • desktop — Desktop browser
  • mobile — Mobile phone
  • tablet — Tablet device
  • robot — Bot / crawler
  • other — Unknown
  • 10.0.0.5010.0.0.0
  • 172.16.5.99172.16.5.0
  • ::1::
  • 2001:db8::12001:db8::

:::

Testing

Run the Pest test suite to verify everything works correctly:

$ composer test