Skip to content

Commit

Permalink
docs: Add guide on how to make an entity channel aware (#3209)
Browse files Browse the repository at this point in the history
  • Loading branch information
Draykee authored Jan 22, 2025
1 parent b8112be commit 7e90ddc
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/docs/guides/core-concepts/channels/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Many entities are channel-aware, meaning that they can be associated with a mult

- [`Asset`](/reference/typescript-api/entities/asset/)
- [`Collection`](/reference/typescript-api/entities/collection/)
- [`Customer`](/reference/typescript-api/entities/customer-group/)
- [`Customer`](/reference/typescript-api/entities/customer/)
- [`Facet`](/reference/typescript-api/entities/facet/)
- [`FacetValue`](/reference/typescript-api/entities/facet-value/)
- [`Order`](/reference/typescript-api/entities/order/)
Expand Down
116 changes: 116 additions & 0 deletions docs/docs/guides/developer-guide/channel-aware/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
title: "Implementing ChannelAware"
showtoc: true
---

## Defining channel-aware entities

Making an entity channel-aware means that it can be associated with a specific [Channel](/reference/typescript-api/channel/).
This is useful when you want to have different data or features for different channels. First you will have to create
an entity ([Define a database entity](/guides/developer-guide/database-entity/)) that implements the `ChannelAware` interface.
This interface requires the entity to provide a `channels` property

```ts title="src/plugins/requests/entities/product-request.entity.ts"
import { DeepPartial } from '@vendure/common/lib/shared-types';
import { VendureEntity, Product, EntityId, ID, ChannelAware } from '@vendure/core';
import { Column, Entity, ManyToOne } from 'typeorm';

@Entity()
class ProductRequest extends VendureEntity implements ChannelAware {
constructor(input?: DeepPartial<ProductRequest>) {
super(input);
}

@ManyToOne(type => Product)
product: Product;

@EntityId()
productId: ID;

@Column()
text: string;
// highlight-start
@ManyToMany(() => Channel)
@JoinTable()
channels: Channel[];
// highlight-end
}
```

## Creating channel-aware entities

Creating a channel-aware entity is similar to creating a regular entity. The only difference is that you need to assign the entity to the current channel.
This can be done by using the `ChannelService` which provides the `assignToCurrentChannel` helper function.

:::info
The `assignToCurrentChannel` function will only assign the `channels` property of the entity. You will still need to save the entity to the database.
:::

```ts title="src/plugins/requests/service/product-request.service.ts"
import { ChannelService } from '@vendure/core';

export class RequestService {

constructor(private channelService: ChannelService) {}

async create(ctx: RequestContext, input: CreateRequestInput): Promise<ProductRequest> {
const request = new ProductRequest(input);
// Now we need to assign the request to the current channel (+ default channel)
// highlight-next-line
await this.channelService.assignToCurrentChannel(input, ctx);

return await this.connection.getRepository(ProductRequest).save(request);
}
}
```
For [Translatable entities](/guides/developer-guide/translations/), the best place to assign the channels is inside the `beforeSave` input of the [TranslateableSave](/reference/typescript-api/service-helpers/translatable-saver/) helper class.


## Querying channel-aware entities

When querying channel-aware entities, you can use the [ListQueryBuilder](/reference/typescript-api/data-access/list-query-builder/#extendedlistqueryoptions) or
the [TransactionalConnection](/reference/typescript-api/data-access/transactional-connection/#findoneinchannel) to automatically filter entities based on the provided channel id.


```ts title="src/plugins/requests/service/product-request.service.ts"
import { ChannelService, ListQueryBuilder, TransactionalConnection } from '@vendure/core';

export class RequestService {

constructor(
private connection: TransactionalConnection,
private listQueryBuilder: ListQueryBuilder,
private channelService: ChannelService) {}

findOne(ctx: RequestContext,
requestId: ID,
relations?: RelationPaths<ProductRequest>) {
// highlight-start
return this.connection.findOneInChannel(ctx, ProductRequest, requestId, ctx.channelId, {
relations: unique(effectiveRelations)
});
// highlight-end
}

findAll(
ctx: RequestContext,
options?: ProductRequestListOptions,
relations?: RelationPaths<ProductRequest>,
): Promise<PaginatedList<ProductRequest>> {
return this.listQueryBuilder
.build(ProductRequest, options, {
ctx,
relations,
// highlight-next-line
channelId: ctx.channelId,
})
.getManyAndCount()
.then(([items, totalItems]) => {
return {
items,
totalItems,
};
});
}
}
```
1 change: 1 addition & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const sidebars = {
value: 'Advanced Topics',
className: 'sidebar-section-header',
},
'guides/developer-guide/channel-aware/index',
'guides/developer-guide/cache/index',
'guides/developer-guide/dataloaders/index',
'guides/developer-guide/db-subscribers/index',
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/service/services/channel.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ export class ChannelService {
/**
* @description
* Assigns a ChannelAware entity to the default Channel as well as any channel
* specified in the RequestContext.
* specified in the RequestContext. This method will not save the entity to the database, but
* assigns the `channels` property of the entity.
*/
async assignToCurrentChannel<T extends ChannelAware & VendureEntity>(
entity: T,
Expand Down Expand Up @@ -171,7 +172,7 @@ export class ChannelService {

/**
* @description
* Assigns the entity to the given Channels and saves.
* Assigns the entity to the given Channels and saves all changes to the database.
*/
async assignToChannels<T extends ChannelAware & VendureEntity>(
ctx: RequestContext,
Expand Down

0 comments on commit 7e90ddc

Please sign in to comment.