Developer integration guide
Start with installation and Symfony configuration. This guide covers application-level integration after the bundle, routes and resources are working.
Choose an integration surface
| Need | Recommended surface |
|---|---|
| Full file management | /sofinder/browser in manager mode |
| Select one file/image | Browser picker mode and sofinder:select |
| CKEditor 4 | Callback and quick-upload routes in CKEditor guide |
| Custom frontend | Authenticated HTTP API |
| Server-side business logic | Inject FileManager and public contracts |
| New storage backend | StorageAdapterFactoryInterface and storage adapter contract |
Embed manager or picker mode
Presentation query parameters are optional and validated:
/sofinder/browser?uiProfile=standalone
/sofinder/browser?uiProfile=embedded
/sofinder/browser?uiProfile=picker&type=Images&selection=imageuiProfile selects the standalone manager, embedded manager or picker presentation as one coherent setting. uiMode and uiEmbedded remain backward compatible. type chooses the initial resource. selection is any, file or image; an image selection must be web-embeddable. uiTools=common|full keeps picker selection behavior while optionally exposing all ACL-controlled management, detail and image tools. uiHeader, uiLogo, uiSearch, uiLanguage and uiView accept only 0 or 1. These options never add permissions.
For an iframe or same-window picker without CKEditor, listen for the selection event:
window.addEventListener("sofinder:select", (event) => {
const entry = event.detail;
console.log(entry.path, entry.url, entry.mimeType);
});The event is dispatched in the picker window. If the picker is inside an iframe, install the listener on iframe.contentWindow after it loads, or bridge the result with a narrowly scoped same-origin wrapper. SoFinder does not use unrestricted cross-origin postMessage.
Call the HTTP API
Read requests use the current Symfony session. Mutations additionally require the token injected into the browser bootstrap:
const response = await fetch("/sofinder/api/folders", {
method: "POST",
credentials: "same-origin",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"X-CSRF-TOKEN": csrfToken
},
body: JSON.stringify({ resource: "Files", path: "manuals", name: "2026" })
});
const payload = await response.json();
if (!response.ok || !payload.success) throw new Error(payload.error?.message);Do not trust frontend capability flags as authorization. Handle total: null, opaque cursors, partial batch failures, 409 conflict, 413 policy limits, 415 media rejection and 429 with Retry-After. See the complete API reference.
Use FileManager on the server
Inject SohoPHP\SoFinder\FileManager into an application service. Always pass a configured resource name and a logical normalized path, never an absolute storage path.
use SohoPHP\SoFinder\FileManager;
final readonly class DocumentService
{
public function __construct(private FileManager $files) {}
public function openManual(string $path)
{
return $this->files->read('Documents', $path);
}
}FileManager applies resource lookup, path normalization, authorization, quotas, operation gates, storage capabilities, audit events and usage accounting. Prefer it over resolving a storage adapter directly. The returned read value is a stream owned by the caller and must be closed.
Stable entry URLs
Use resource entry_url when storage keys must become application URLs. Route templates can use {resource}, {path}, {name}, {stem}, {extension} and {storage_url}. Implement EntryUrlContextProviderInterface to add host database values such as {id}. The route controller owns its final access policy and may stream through FileManager::read() or redirect to a public provider URL.
Events and application policy
Subscribe to OperationEvent names before.<operation> and after.<operation>. A before subscriber may reject by throwing a domain exception. After events run after storage changes, so notification, indexing and database synchronization must be retry-safe and idempotent. Ignore context keys you do not recognize.
Replace AuthorizationInterface for business-specific resource, operation and normalized-path decisions. Return false for unknown operations. ActorProviderInterface must return a stable opaque ID because it isolates upload sessions, metadata and recycle-bin ownership.
Extension points
- Storage:
StorageAdapterInterface, optional capability interfaces and tagged factories. - State:
ChunkUploadStoreInterface,MetadataStoreInterface,RequestGateStoreInterface,UsageTrackerInterfaceandRecycleBinInterface. - Security:
FileInspectorInterfaceandAuthorizationInterface. - Images:
ImageProcessorInterfaceandImageCapabilityProviderInterface. - UI descriptors:
PluginInterfacetagged withsofinder.plugin. - URLs and audit:
EntryUrlContextProviderInterface,StorageAuditProviderInterfaceand operation events.
Contracts and immutable value objects are listed in PHP contracts. Implementations must be concurrency-safe, keep storage paths and secrets out of exceptions, and throw SoFinderException with a stable machine code for expected domain failures.
Testing an integration
At minimum, automate:
- route import and authenticated access;
- list/create/upload/read/rename/copy/move/delete/restore for each resource class;
- CSRF and role/path-ACL rejection;
- upload extension, MIME, size, quota and conflict cases;
- public versus proxy entry URLs;
- cursor pagination and partial batch results for remote adapters;
- CKEditor callback or custom picker selection;
- security audit and usage recalculation in a production-like environment.
Use the runnable examples/symfony variants as integration fixtures. During deployment run sofinder:security:audit; critical findings must block release.