Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Sybase Laravel Package

uepg/laravel-sybase

Laravel Sybase adds Sybase ASE database support to Laravel, providing a driver connector and query builder so Eloquent and the DB facade work with Sybase via PDO dblib. Configure hosts, credentials, charset, and options in config/database.php.

View on GitHub
Deep Wiki
Context7

Getting Started

What this package is: uepg/laravel-sybase adds a sybase connection driver to Laravel's database layer (SAP ASE / Sybase ASE) so you can use the query builder, DB::connection(), and Eloquent against legacy ASE servers without hand-rolling PDO code. Version 6.x targets modern Laravel on PHP 8.x.

Prerequisites (the part that actually blocks people):

  • ext-pdo_dblib plus FreeTDS (or the vendor Sybase client libraries) installed on the host/container. Confirm with php -m | grep dblib and tsql -H host -p 5000 -U user before touching Laravel config — most "the package doesn't work" reports are a FreeTDS install problem.
  • A reachable ASE instance and a login with rights on the target database.

Install and wire up:

composer require uepg/laravel-sybase:^6.2

Then add a connection block in config/database.php (keep your existing default connection untouched):

'sybase' => [
    'driver'   => 'sybase',
    'host'     => env('DB_SYBASE_HOST'),
    'port'     => env('DB_SYBASE_PORT', '5000'),
    'database' => env('DB_SYBASE_DATABASE'),
    'username' => env('DB_SYBASE_USERNAME'),
    'password' => env('DB_SYBASE_PASSWORD'),
    'charset'  => env('DB_SYBASE_CHARSET', 'utf8'),
    'appname'  => env('DB_SYBASE_APPNAME', 'Laravel'),
],

Where to look first:

  1. config/database.php — the connection array above is the whole contract.
  2. vendor/uepg/laravel-sybase/src/ — read SybaseConnector, SybaseConnection, and SybaseGrammar. The grammar file is your source of truth for which builder methods actually compile on ASE.
  3. vendor/uepg/laravel-sybase/README.md for any version-specific config keys.

First use case: a read-only reporting screen against the legacy ASE box. Use the non-default connection explicitly:

$rows = DB::connection('sybase')
    ->table('dbo.customers')
    ->select(['cust_id', 'cust_name', 'created_dt'])
    ->limit(25)
    ->get();

That single call proves the extension, FreeTDS, credentials, charset, and grammar all line up. Do it before you write a single model.

Implementation Patterns

Always name the connection; never make Sybase the default. Legacy ASE is almost always a secondary system. Keep MySQL/Postgres as default and reach for DB::connection('sybase') or Model::on('sybase'). This keeps migrate, RefreshDatabase, and queue/session tables working normally.

Eloquent models for legacy tables need de-Laravelizing:

class LegacyCustomer extends Model
{
    protected $connection = 'sybase';
    protected $table      = 'dbo.customers';
    protected $primaryKey = 'cust_id';
    public    $timestamps = false;   // almost always true for legacy schemas
    public    $incrementing = false; // non-identity keys
    protected $guarded = [];
    protected $casts = ['created_dt' => 'datetime', 'balance' => 'float'];
}

If a table has a composite key, drop Eloquent and stay on the query builder — a half-working model is worse than none.

Hide the database behind a repository interface. The rest of your app should depend on CustomerRepository, with a SybaseCustomerRepository and a fake/array implementation for tests. This is the single highest-leverage pattern here: it lets you write the Laravel-side features normally and swap the legacy source later without touching controllers.

Multiple ASE servers/databases: duplicate the block with a distinct key (sybase_reporting) and pass the name through the repository constructor. There is no cross-database join across ASE and your primary DB — land data in a local staging table in batched insertOrIgnore/upsert calls, then join locally with real Laravel SQL.

Large extracts: prefer cursor(), lazy(), or chunkById() over get(). And use simplePaginate() — paginate() fires a count(*) that can be brutal on an unindexed legacy table.

Read-only by convention, not by accident. Give the Sybase login read-only grants at the database level. It prevents a future ->delete() from being a career event and documents the intent.

Testing: bind a fake repository in the container for feature tests, and gate any test that touches the real ASE behind @group sybase / markTestSkipped() so CI without FreeTDS still runs green.

Gotchas and Tips

The 6.2 change is an encoding fix — pin ^6.2 if you store non-ASCII text. Prior behavior could mangle accented/CJK data on both read and write (classic é instead of é, or truncation at a converted byte boundary). Upgrading from 6.0/6.1 is low risk: the changelog is a single commit, no breaking changes, no config key removals. Verify on upgrade with:

DB::connection('sybase')->select("SELECT 'Grüße — 東京' AS t");

If that round-trips, encoding is healthy.

Charset exists in two places and both must agree. The charset in config/database.php and the FreeTDS client charset in freetds.conf (or TDSVER/FREETDSCONF env). Mismatched settings cause double conversion — mojibake in, mojibake out, and it looks like a package bug. utf8 in config + UTF-8 in FreeTDS is the pairing you want.

Schema/migrations are not a reliable path. Treat ASE as an external schema owned by someone else. Manage it out-of-band; don't plan on Schema::connection('sybase')->create().

String semantics differ from MySQL: char/varchar comparison pads with spaces, so '' can behave like a single space. Call trim() on read, and never validate "empty" against a raw fetched value.

upsert / ON DUPLICATE KEY won't translate. Use updateOrInsert() or an explicit UPDATE-then-INSERT inside DB::connection('sybase')->transaction(...). Verify savepoints before nesting transactions — nested transaction support depends on the grammar.

Binds can be sent as strings by pdo_dblib, which triggers implicit-conversion errors or index-ignoring scans on numeric columns. Cast in PHP ((int) $id) before binding, or use whereRaw('cust_id = ?', [(int) $id]).

Dates: ASE datetime often arrives as a non-ISO string. Explicit $casts (or Carbon::parse() with a known format) prevents the InvalidFormatException class of bug.

Debugging toolkit:

  • DB::connection('sybase')->listen(fn ($q) => logger($q->sql, $q->bindings));
  • ->dump() / ->dd() on the builder for the compiled SQL — the fastest way to see how the grammar rewrote your limit/offset.
  • TDSDUMP=/tmp/tds.log to trace the FreeTDS protocol layer when connections fail below Laravel.

Extension point: if you need session options (SET ANSI_NULLS ON, quoted_identifier, lock timeouts), the clean hook is DB::extend('sybase_ro', fn ($config, $name) => ...) in a service provider that wraps the package connector and issues the setup statements post-connect. Prefer that over editing vendor code.

Connection lifetime: long-lived queue workers will hold idle ASE connections that the server may reap. Add a timeout in options and expect occasional Could not connect on the first job after idle — retry once in the repository rather than assuming a fatal error.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums