PHPackages                             basedon/laravel-mssql-case-adapter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. basedon/laravel-mssql-case-adapter

ActiveLibrary[Database &amp; ORM](/categories/database)

basedon/laravel-mssql-case-adapter
==================================

Transparent snake\_case to UPPERCASE identifier mapping for legacy SQL Server databases in Laravel.

v0.1.0(1mo ago)08MITPHPPHP ^8.2CI passing

Since Jul 12Pushed 1mo agoCompare

[ Source](https://github.com/hackeru2/laravel-mssql-case-adapter)[ Packagist](https://packagist.org/packages/basedon/laravel-mssql-case-adapter)[ RSS](/packages/basedon-laravel-mssql-case-adapter/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (3)Versions (2)Used By (0)

Laravel MSSQL Case Adapter
==========================

[](#laravel-mssql-case-adapter)

[![tests](https://github.com/hackeru2/laravel-mssql-case-adapter/actions/workflows/tests.yml/badge.svg)](https://github.com/hackeru2/laravel-mssql-case-adapter/actions/workflows/tests.yml)

Write clean, snake\_case Laravel code against legacy **UPPERCASE** SQL Server schemas.

Legacy enterprise MSSQL databases often use strict uppercase naming (`SITES`, `SITE_ID`, `USER_FIRST_NAME`). Writing `$user->USER_FIRST_NAME` ruins the developer experience and fights every Eloquent convention — especially **relationships and eager loading**. This package translates identifiers transparently at the database driver and grammar layer: your models, relations, and queries stay 100% lowercase, and the package converts both directions automatically.

```
class Site extends Model            // table SITES (SITE_ID, SITE_NAME)
{
    public function user(): HasOne
    {
        return $this->hasOne(User::class, 'site_id');   // column SITE_ID on USERS
    }
}

Site::with('user')->where('site_name', 'HQ')->get();
// select * from [SITES] where [SITE_NAME] = ?
// select * from [USERS] where [USERS].[SITE_ID] in (...)
// → models hydrate with lowercase attributes: $site->site_name, $site->user->user_id
```

> **Live demo:** see [hackeru2/legacy-mssql-demo-app](https://github.com/hackeru2/legacy-mssql-demo-app) — a full Laravel 13 JSON API (relations, pivots, nested eager loading) running against an UPPERCASE SQL Server schema, CI-tested on both default and case-sensitive collations.

Installation
------------

[](#installation)

```
composer require basedon/laravel-mssql-case-adapter
```

Point your connection at the `mssql-adapted` driver — everything else is a standard `sqlsrv` config:

```
// config/database.php
'connections' => [
    'legacy' => [
        'driver'   => 'mssql-adapted',
        'host'     => env('DB_HOST', 'localhost'),
        'database' => env('DB_DATABASE'),
        'username' => env('DB_USERNAME'),
        'password' => env('DB_PASSWORD'),
        // 'trust_server_certificate' => true,
    ],
],
```

That's it. No traits, no per-model configuration.

How it works
------------

[](#how-it-works)

LayerMechanismQueries outA custom query grammar translates every table, column, and alias through the identifier resolver before wrapping it in `[...]` — selects, wheres, joins, order by, inserts, updates, and relationship constraints included.Results in`PDO::ATTR_CASE => PDO::CASE_LOWER` is merged into the connection options (covers raw `DB::select()` too), and the query post-processor maps result keys through the resolver as a safety net.SchemaThe schema grammar translates identifiers as well, so `Schema::hasTable('sites')` and migrations work — including under case-sensitive collations.> **Do I even need this?** Under SQL Server's default case-insensitive collations, identifier *matching* already works; the pain is result hydration and Eloquent relationship key matching, which this package fixes. Under case-**sensitive** (binary) collations, the grammar translation is what makes lowercase queries work at all. CI runs the full suite against both.

Custom naming strategies
------------------------

[](#custom-naming-strategies)

The default `UppercaseResolver` maps `site_name ↔ SITE_NAME`. For prefixed or irregular legacy schemas (e.g. `orders` → `TBL_ORDERS`), implement the contract and register it:

```
use Basedon\MssqlCaseAdapter\Resolvers\IdentifierResolver;

class TblPrefixResolver implements IdentifierResolver
{
    public function toDatabase(string $identifier): string
    {
        return 'TBL_'.strtoupper($identifier);
    }

    public function toApplication(string $identifier): string
    {
        return strtolower(preg_replace('/^TBL_/', '', $identifier));
    }
}
```

```
// Globally, in config/mssql-case-adapter.php (php artisan vendor:publish --tag=mssql-case-adapter-config)
'identifier_resolver' => TblPrefixResolver::class,

// …or per connection:
'legacy' => [
    'driver' => 'mssql-adapted',
    'identifier_resolver' => TblPrefixResolver::class,
    // ...
],
```

The resolver must be bijective for the identifiers you use: `toApplication(toDatabase($x)) === $x`.

Generating models from a legacy schema
--------------------------------------

[](#generating-models-from-a-legacy-schema)

```
php artisan mssql:inspect --connection=legacy --path=app/Models --namespace="App\Models"
```

Scans `INFORMATION_SCHEMA` and generates Eloquent model stubs with the right `$connection`, `$table` (only when not derivable), `$primaryKey`, `$casts`, and `$timestamps` — all in lowercase application naming.

Configuration
-------------

[](#configuration)

KeyDefaultMeaning`identifier_resolver``UppercaseResolver::class`Naming strategy (global or per connection).`pdo_case_lower``true`Merge `PDO::ATTR_CASE => CASE_LOWER` into options (per connection: `case_lower`). An explicit `PDO::ATTR_CASE` in the connection `options` always wins.`normalize_results``true`Post-processor maps result keys through the resolver.Limitations
-----------

[](#limitations)

- **Raw SQL bypasses the grammar.** `DB::raw()`, `selectRaw()`, `orderByRaw()`, `DB::statement()` are passed through untouched — write database-side (UPPERCASE) identifiers in raw fragments. Result keys of raw *selects* are still lowercased by the PDO case option.
- **Mixed-case application identifiers** (`siteName`) are not round-trippable with the default resolver; stick to snake\_case (Laravel convention) or supply a custom resolver.

Testing
-------

[](#testing)

```
composer test        # unit + feature (no database needed)
composer analyse     # larastan, level 5
composer format      # pint
```

Integration tests run in GitHub Actions against a real `mcr.microsoft.com/mssql/server:2022` container with uppercase tables, on both a default-collation database and a `Latin1_General_BIN` (case-sensitive) database.

License
-------

[](#license)

MIT

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance90

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 Bus Factor1

Top contributor holds 50% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

49d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/47e9bde57d09d10f8d3261b01907cbd80ad5a8c55901a07812a67a181fd2cb09?d=identicon)[hackeru2](/maintainers/hackeru2)

---

Top Contributors

[![amir-1004](https://avatars.githubusercontent.com/u/35829077?v=4)](https://github.com/amir-1004 "amir-1004 (4 commits)")[![hackeru2](https://avatars.githubusercontent.com/u/35829077?v=4)](https://github.com/hackeru2 "hackeru2 (4 commits)")

---

Tags

laravelmssqleloquentsql serverlegacycase mapping

### Embed Badge

![Health badge](/badges/basedon-laravel-mssql-case-adapter/health.svg)

```
[![Health](https://phpackages.com/badges/basedon-laravel-mssql-case-adapter/health.svg)](https://phpackages.com/packages/basedon-laravel-mssql-case-adapter)
```

###  Alternatives

[spatie/laravel-medialibrary

Associate files with Eloquent models

6.2k47.7M734](/packages/spatie-laravel-medialibrary)[laravel/ai

The official AI SDK for Laravel.

1.1k6.4M360](/packages/laravel-ai)[spatie/laravel-health

Monitor the health of a Laravel application

89313.5M195](/packages/spatie-laravel-health)[illuminate/queue

The Illuminate Queue package.

20433.5M1.9k](/packages/illuminate-queue)[psalm/plugin-laravel

Psalm plugin for Laravel

3365.5M359](/packages/psalm-plugin-laravel)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8793.4M27](/packages/yajra-laravel-oci8)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
