|
| 1 | +# Repositories |
| 2 | +Repositories provide a structured way to manage data operations in the Backoffice. They abstract the data access layer, allowing for easier reuse and scalability. |
| 3 | + |
| 4 | +Repositories create separation between domain logic and data access. By providing a known interface for data requests, we can reuse UI components across different domains. For example, we have a generic UX flow for deleting an entity. By supplying this flow with a repository that has a known interface for deletion, we can use the same UX flow to delete any entity. The same applies to Trees, Collections, Workspaces, and more. |
| 5 | + |
| 6 | +Additionally, repositories can utilize different data sources depending on the application's state. These sources may include: |
| 7 | + |
| 8 | +* A REST API |
| 9 | +* Offline storage |
| 10 | +* A local cache |
| 11 | +* And more. |
| 12 | + |
| 13 | +This abstraction ensures that consumers don’t need to worry about how to access data. The repository serves as the Backoffice’s entry point for requesting new data. As a result, we achieve a loosely coupled connection between consumers and data storage procedures, effectively hiding complex implementations. |
| 14 | + |
| 15 | +* **Repository:** defines what data operations are available (get, add, update, delete). |
| 16 | +* **Data Source:** defines how data is fetched or stored. |
| 17 | + |
| 18 | +### Data flow with a repository <a href="#data-flow-with-a-repository" id="data-flow-with-a-repository"></a> |
| 19 | + |
| 20 | +A repository must be instantiated where it is used. It should take an [UmbController](../umbraco-controller/README.md) as part of the constructor. This ensures that any contexts consumed in the repository are scoped correctly. |
| 21 | + |
| 22 | +A repository can be initialized directly from an element, but will often be instantiated in a [context](../context-api/README.md), like the Workspace Context. |
| 23 | + |
| 24 | +The data flow when using a repository can be illustrated as follows: |
| 25 | + |
| 26 | +```text |
| 27 | +(Data Source) -> Repository -> (Controller/Context) -> Element |
| 28 | +``` |
| 29 | + |
| 30 | +### Using an existing Repository <a href="#using-a-repository" id="using-a-repository"></a> |
| 31 | + |
| 32 | +Often, you will find that data is already available and observable in a [context](../contexts/README.md). In that case, subscribing to the context [state](../states.md) will be the right approach to take. This way, you will receive all runtime updates that occur to the data throughout the session. |
| 33 | + |
| 34 | +If the needed data isn’t available in a context, use a repository to request the data. This will give you the correct data no matter the current application state. |
| 35 | + |
| 36 | +In the example below, we instantiate the `UmbDocumentItemRepository` directly in a custom element to request Document Item data by its unique key. |
| 37 | + |
| 38 | +```typescript |
| 39 | +import { LitElement} from '@umbraco-cms/backoffice/external/lit'; |
| 40 | +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; |
| 41 | +import { UmbDocumentItemRepository } from '@umbraco-cms/backoffice/document'; |
| 42 | + |
| 43 | +// Simplified element |
| 44 | +class MyElement extends UmbElementMixin(LitElement) { |
| 45 | + ... |
| 46 | + #documentItemRepository = new UmbDocumentItemRepository(this); |
| 47 | + |
| 48 | + firstUpdated() { |
| 49 | + const { data, error } = await this.#documentItemRepository.requestItems(['some-unique-key', 'another-unique-key']); |
| 50 | + console.log('Response', data, error); |
| 51 | + // Render data in the element |
| 52 | + } |
| 53 | + ... |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +Alternatively, you can instantiate the repository in a [controller](../umbraco-controller/README.md) or [context](../context-api/README.md), store the data in a [state](../states.md), and then observe that state in your element. This is often the preferred approach as it allows for better separation of concerns and reusability across different components. |
| 58 | + |
| 59 | +```typescript |
| 60 | +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; |
| 61 | +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; |
| 62 | +import { UmbDocumentItemRepository } from '@umbraco-cms/backoffice/document'; |
| 63 | + |
| 64 | +export class MyController extends UmbControllerBase { |
| 65 | + |
| 66 | + #items = new UmbArrayState<DocumentItemModel>([]); |
| 67 | + items = this.#items.asObservable(); |
| 68 | + |
| 69 | + #documentItemRepository = new UmbDocumentItemRepository(this); |
| 70 | + |
| 71 | + constructor(host: UmbControllerHost) { |
| 72 | + super(host); |
| 73 | + this.#load(); |
| 74 | + } |
| 75 | + |
| 76 | + async #load() { |
| 77 | + const { data, error } = await this.#documentItemRepository.requestItems(['some-unique-key', 'another-unique-key']); |
| 78 | + console.log('Response', data, error); |
| 79 | + this.#items.setValue(data ?? []); |
| 80 | + // The items state can now be observed by any element initializing this controller |
| 81 | + } |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | + |
| 86 | +### Register a custom Repository <a href="#register-a-custom-repository" id="register-a-custom-repository"></a> |
| 87 | + |
| 88 | +By registering your repository in the [Extension Registry](../../extending-overview/extension-registry/README.md), you make it available to use in different extension kinds that require a repository alias. |
| 89 | + |
| 90 | +Some of the common repository interfaces are: |
| 91 | +* [UmbDetailRepository](./repository-types/detail-repository.md) - for detail views of a single entity. |
| 92 | +* [UmbCollectionRepository](./repository-types/collection-repository.md) - for collection views of multiple entities. |
| 93 | +* [UmbTreeRepository](./repository-types/tree-repository.md) - for tree structures of entities. |
| 94 | +* [UmbItemRepository](./repository-types/item-repository.md) - for item requests. |
| 95 | + |
| 96 | +See the example below of how to register a custom repository: |
| 97 | + |
| 98 | +```typescript |
| 99 | +import { umbExtensionsRegistry } from "@umbraco-cms/backoffice/extension-registry"; |
| 100 | +import { UmbRepositoryBase } from "@umbraco-cms/backoffice/repository"; |
| 101 | +import type { UmbTreeRepository } from "@umbraco-cms/backoffice/tree"; |
| 102 | + |
| 103 | +class MyEntityTreeRepository extends UmbRepositoryBase implements UmbTreeRepository { |
| 104 | + // Implement repository methods here |
| 105 | +} |
| 106 | + |
| 107 | +const repositoryManifest = { |
| 108 | + type: "repository", |
| 109 | + alias: "My.Repository.EntityTree", |
| 110 | + name: "My Entity Tree Repository", |
| 111 | + api: MyEntityTreeRepository, |
| 112 | +}; |
| 113 | + |
| 114 | +umbExtensionsRegistry.register(repositoryManifest); |
| 115 | +``` |
| 116 | + |
0 commit comments