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

Banking Laravel Package

byrokrat/banking

PHP library for Swedish banking data: validate, format, and work with account and clearing numbers, Bankgiro and PlusGiro numbers, BIC/SWIFT codes, OCR references, and monetary amounts for payment integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require byrokrat/banking

That is the whole install. There is no service provider, no config file, no facade — the package is a set of plain immutable PHP value objects plus factories. It drops into Laravel without any wiring, which is exactly why it is pleasant for a small set of well-defined problems.

Version 2.2.3 requires PHP >=7.3 and officially supports up to PHP 8.0. It is a maintenance release with no API changes: if you are already on 2.x, the upgrade is safe. If you are on PHP 8.0 you need at least this version — earlier 2.x releases failed there.

Where to look first:

  1. README.md — one screen of usage, enough to get moving.
  2. src/ — the API surface is tiny and self-documenting; the Exception namespace tells you everything about failure modes.
  3. tests/ — this is the real specification. It is exhaustive over Swedish bank clearing ranges and check-digit algorithms, and it makes a good fixture source for your own test suite.

The canonical first use case is validating an account number typed by a user on an invoice, payout or direct-debit form:

use Byrokrat\Banking\AccountFactory;
use Byrokrat\Banking\Exception\InvalidAccountNumberException;

try {
    $account = (new AccountFactory)->createAccount('5001-2345');

    $account->getBankName();       // bank owning the clearing range
    $account->getClearingNumber(); // e.g. "5001"
    $account->getSerialNumber();   // e.g. "2345"
    $account->getCheckDigit();     // computed/validated check digit
} catch (InvalidAccountNumberException $e) {
    // descriptive message about *why* it failed
}

The sibling types — clearing numbers, Bankgiro, Plusgiro, OCR references and BIC codes — follow the same shape: a factory parses a string, returns an immutable value object, and throws a descriptive exception on bad input. Confirm the exact factory/formatter class names against src/ once; the API is small and consistent across types.

Implementation Patterns

Bind the factories in the container. They are cheap and stateless, but binding them keeps your call sites clean and makes them swappable in tests:

// AppServiceProvider::register()
$this->app->singleton(\Byrokrat\Banking\AccountFactory::class);

A dedicated validation rule beats inline parsing. Keep the parsing details out of controllers:

class SwedishAccountNumber implements ValidationRule
{
    public function __construct(private AccountFactory $factory) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        try {
            $this->factory->createAccount(preg_replace('/\D/', '', (string) $value));
        } catch (InvalidAccountNumberException) {
            $fail('The :attribute is not a valid Swedish account number.');
        }
    }
}

Parse at the boundary, carry the value object inward. Turn the raw request string into an Account/Bankgiro in a FormRequest or an action, and let everything downstream depend on the object rather than a string. That is the whole point of the library: the invariant "this is a valid Swedish number" is proven once and never re-checked.

Store canonical digits, format on output. Persist the unformatted digits in a string column (never an integer — leading zeros are part of the number), and use the package's Byrokrat\Banking\Formatter classes to render the display form. getNumber() gives you a normalized grouped representation for API resources and PDFs.

Use an Eloquent cast for round-tripping.

public function get($model, $key, $value, $attributes)
{
    return $value === null ? null : app(AccountFactory::class)->createAccount($value);
}

public function set($model, $key, $value, $attributes)
{
    return [$key => $value instanceof AccountNumber
        ? $value->getClearingNumber() . $value->getSerialNumber()
        : $value];
}

Batch imports must not abort on the first bad row. Wrap each row in its own try/catch, collect (row, raw input, exception message) into a failure report, and import the good rows. This is the single most valuable pattern for data migrations from legacy ledgers.

Payment file generation. A payout run typically needs account number + BIC + Bankgiro, with the OCR reference attached to the remittance line. The library gives you validated components and the bank name/BIC metadata you need to route the payment, so keep the objects (not strings) on your payment DTO.

Gotchas and Tips

  • Clearing ranges are ambiguous. The same clearing number digits can map to several banks, and some ranges are shared or generically assigned. The getBankName() you get back is the best guess the hardcoded table can make — do not use it as a hard routing key for money movement.
  • Strip separators yourself. Hyphens, spaces and non-breaking spaces from copy-pasted input are a common source of false negatives. preg_replace('/\D/', '', $value) before parsing removes almost all of it.
  • Never cast to int. Clearing numbers and serial numbers routinely begin with zeros.
  • Exceptions are descriptive but untranslated. Catch the specific types under Byrokrat\Banking\Exception, log getMessage() plus the raw input, and surface your own localized message to users.
  • Bankgiro and Plusgiro look alike but are not. They use different length rules and check-digit algorithms; choose the parser based on the payment rail, not on what the number looks like. A rejected number is usually the wrong parser, not a bad number.
  • BIC validation is structural only. It confirms 8/11 characters and shape, not that the institution exists or that the account is reachable. Pair it with your own bank-directory check if routing matters.
  • Mind the PHP version matrix. 2.2.3 bumped the minimum to PHP 7.3 and fixed PHP 8.0 support; nothing newer is covered by the release. On PHP 8.1+ you are outside the tested matrix — run your own fixture tests in CI after every PHP upgrade, not just after package upgrades.
  • The bank table is hardcoded in source. A new bank or changed clearing range requires a dependency bump or a fork. 2.2.3 is a maintenance release (PHP 8 support, PHPUnit 9 in the build) and does not touch the bank data, so the table is as old as the last feature release. Pin the version and re-run your own fixture tests after any update.
  • Custom casts don't get container injection. Laravel instantiates cast classes without resolving constructor dependencies, which is why the example above uses app() inside the cast rather than type-hinting the factory.
  • Extension points live in Format and Validator. If a bank is missing, you can compose the format/validator primitives rather than patching vendor code.
  • Tests are the documentation. When behaviour surprises you, read the data providers in the package's own tests before opening an issue — they encode the exact intent per bank and per number type.
  • Upgrading 2.x → 2.2.3 is a no-op for your code. No signatures, exceptions or value-object behaviour changed. The only visible effect is on your composer.json PHP constraint if you were still allowing 7.2.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle