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 Onoffice Adapter Laravel Package

innobrain/laravel-onoffice-adapter

Laravel adapter for the onOffice API that makes it easy to connect your PHP application to onOffice CRM data, including real estate listings, contacts, and addresses, through a clean, framework-friendly integration layer.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and let auto-discovery do its job.

    composer require innobrain/laravel-onoffice-adapter
    php artisan vendor:publish --tag=onoffice-config
    

    Laravel's package discovery should register the service provider; if you're on an older skeleton, add it manually to config/app.php.

  2. Fill in credentials before touching any code. Open the published config/onoffice.php first — this is the single most informative file in the package. You'll typically need the onOffice API URL, an API token, and a secret (exact env key names vary; copy them from the config rather than guessing). Put them in .env and never commit them.

  3. Read the source in this order when the README is thin: config/onoffice.php → the service provider (what gets bound into the container) → the main client class → any facade. The public surface of a package this small is usually 1–3 classes; you can read all of it in fifteen minutes.

  4. First use case: read a page of estates.

    $response = app(OnOfficeClient::class)->call('read', [
        'resource' => 'estate',
        'listlimit' => 10,
    ]);
    

    Verify the exact method signature against the source — the point is to confirm credentials, connectivity, and response shape with a single read before building anything on top. Log the raw response once, then never again.

Implementation Patterns

Wrap the adapter, don't sprinkle it. Create your own OnOfficeRepository (or per-domain services like EstateRepository, AddressRepository) that injects the package client. Your app code should never see onOffice's request/response arrays. This is the difference between a one-week integration and a one-year liability.

Map responses to DTOs, not arrays. The onOffice API returns stringly-typed data with German-flavoured field names. Run responses through a mapper (EstateData::fromArray($row)) so nullability, casting, and field renames live in one place. When onOffice renames a field, you change one mapper instead of forty call sites.

Treat filters and sorting as first-class objects. The API expects structured filter arrays ([['op' => '=', 'field' => 'status', 'value' => 1]]-style). Build a small query builder or value objects around this rather than hand-writing nested arrays at every call site — it makes filters testable and reusable across list views and exports.

Batch activity reads instead of looping. Since v2.8.0 the activity read accepts multiple estate IDs via estateIds(), so you can pull the activity stream for a whole set of estates in one request rather than issuing one call per estate:

// prefer this over a foreach of single-estate activity reads
$activities = $client->call('read', [
    'resource' => 'activity',
    'estateIds' => $estateIds,
]);

Chunk large ID lists (the underlying API still returns a bounded result set per request) and treat this as your default for dashboards, timelines, and "recent activity" widgets. It is additive — nothing to migrate — but existing loop-based code is now the slow path.

Cache reference data aggressively. Field lists, filter options (getfilter), and lookup tables change rarely and are expensive to fetch. Cache them for hours with Cache::remember, and key the cache by credential/tenant if you support more than one onOffice account.

Move writes and bulk syncs to queues. Creates, modifies, and multi-page estate/address syncs belong in jobs with $tries, backoff, and failed() handlers. onOffice is a CRM, not your primary datastore — a slow or failed write must never block a web request.

Test with Http::fake(). Because the adapter ultimately speaks HTTP, you can fake at the boundary and assert on the outgoing XML/JSON payload without hitting the real API. Bind a fake client into the container in your TestCase and write contract tests for your repository layer. Include a fixture for the multi-estate activity request so a future release doesn't quietly change its shape.

Isolate multi-tenant credentials. If different sites use different onOffice accounts, resolve credentials per-tenant (a config repository or a scoped binding) rather than reading config() inside the client. Otherwise you'll leak estates between customers — the worst possible bug in this domain.

Gotchas and Tips

  • HTTP 200 does not mean success. The onOffice API commonly reports errors inside a successful response body. Always inspect the error/status section of the payload and throw a domain exception; don't rely on $response->successful().
  • Pagination is offset/limit, and the default limit is small. Loop until you get fewer rows than your limit, and be explicit about listlimit/listoffset (or the package's equivalent). Silent truncation is the classic "why are only 20 estates showing?" bug — this applies to multi-estate activity reads too, so don't assume estateIds() returns an unbounded stream.
  • Everything is a string. Numbers, booleans, and dates arrive as strings; empty fields may be "" or absent. Normalise in your mapper, not in Blade templates.
  • Rate limits and IP restrictions are real. onOffice accounts can be limited by requests-per-day and sometimes by whitelisted IPs. Add retry-with-backoff for transient failures, and check limits before writing a bulk sync that pages through thousands of records.
  • Field names are German and unstable across modules. Keep a translation layer; don't expose veroeffentlichen or objektnr_extern to your frontend.
  • Invalidate caches on write. After a successful modify, forget the relevant cache keys. Stale reference data is easy to introduce and hard to notice.
  • Pin the version and watch the repo. With 5 stars and zero dependents, the bus factor is effectively one. Use a caret constraint but read the changelog before minor bumps — 2.8.0 is a good example of a small additive change worth skimming for — and keep your own integration tests so you can upgrade with confidence. If the package stalls, your repository wrapper is the seam that lets you swap in a hand-rolled HTTP client in a day.
  • Log correlation IDs. Attach the onOffice request identifier to your logs so support tickets can be traced both ways. Without this, debugging a failed write against a third-party CRM is guesswork.
  • Extension points to lean on: container bindings (override the client in tests or for a custom transport), the publishable config (timeouts, logging, cache TTL), and Laravel's HTTP client events for global logging. Avoid forking the package unless you're prepared to maintain it.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
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