Projektové rozšíření schématu publikovaných dat

Projektové rozšíření schématu publikovaných dat

Schéma publikovaných dat může být projektově rozšiřováno. Níže je popsán postup na příkladu rozšíření produktu.

Zkopírovat odkaz na sekci1. Rozhraní entity

Prvním krokem je definovat rozhraní produktu. Entita produktu bude reprezentována tímto rozhraním napříč celým systémem.

java
1 public interface DemoPublishedProduct extends2		PublishedProductContract<DemoPublishedProduct, DemoPublishedProductEditor>,3		DemoPublishedProductContract {4}

Toto produktové rozhraní musí dědit základní rozhraní com.fg.cps.eshop.product.publishing.model.PublishedProductContract a projektové rozhraní DemoPublishedProductContract.

Projektové rozhraní DemoPublishedProductContract obsahuje definici rozšiřujícího schématu. V tomto případě se jedná o atribut demoNumber.

java
1 public interface DemoPublishedProductContract {2
3    String ATTRIBUTE_DEMO_NUMBER = "demoNumber";4
5    /**6     * [cs] Ukázkový atribut rozšiřující {@link com.fg.cps.eshop.product.publishing.model.PublishedProduct}. Nemusí být unikátní.7     *8     * @throws ContextMissingException if the attributes were not fetched along with entity (or this particular attribute was not fetched)9     */10    @Attribute(11            name = ATTRIBUTE_DEMO_NUMBER,12            description = "Custom demo attribute. It doesn't have to be unique.",13            filterable = true,14            sortable = true,15            nullable = true,16            representative = true17    )18    @Nullable19    String getDemoNumber() throws ContextMissingException;20
21}

Při extenzi základního rozhraní PublishedProductContract se uvádějí 2 generické typy. První je projektové rozhraní entity, v našem případě DemoPublishedProduct. Druhé je rozhraní editoru, tedy rozhraní pomocí kterého lze v rámci snippetů projektová data do publikovaných dat zapisovat (indexovat).

Zkopírovat odkaz na sekci2. Editor

Rozhraní editoru DemoPublishedProductEditor musí extendovat základní rozhraní editoru PublishedProductEditorContract a projektové rozhraní editoru DemoPublishedProductContract, viz příklad.

java
1 public interface DemoPublishedProductEditor extends2		PublishedProductEditorContract<DemoPublishedProduct, DemoPublishedProductEditor>,3		DemoPublishedProductContract4{5
6	/**7	 * @param demoNumber demo-number of entity8	 * @throws ContextMissingException if the attribute was not fetched along with entity9	 */10	@AttributeRef(ATTRIBUTE_DEMO_NUMBER)11	void setDemoNumber(@Nullable String demoNumber) throws ContextMissingException;12}

Zkopírovat odkaz na sekci3. Servisa (publikovaná data)

Dále je potřeba připravit servisu, pomocí které lze na projektu přistupovat k projektovým datům. Tato servisa musí extendovat základní servisu entity, např. pro produkt je to AbstractPublishedProductService.

java
1 public class DemoPublishedProductService extends AbstractPublishedProductService<DemoPublishedProduct, DemoPublishedProductEditor> {2
3	public DemoPublishedProductService(4			@NonNull EvitaContract evita,5			@NonNull ReflectionLookup reflectionLookup,6			@NonNull WrappingService wrappingService7	) {8		super(evita, reflectionLookup, wrappingService);9	}10
11	@Override12	public @NonNull Class<DemoPublishedProduct> getEntityClass() {13		return DemoPublishedProduct.class;14	}15
16	@Override17	public @NonNull Class<DemoPublishedProductEditor> getEntityEditorClass() {18		return DemoPublishedProductEditor.class;19	}20}

Zkopírovat odkaz na sekci4. Publikační snippet (publikovaná data)

Indexace projektových dat se zajistí pomocí snippetu.

java
1 public class DemoPublishedProductConversionSnippet implements EntityToEvitaConversionSnippet<DemoPublishedProductEditor> {2
3	@Override4	public @NonNull Class<DemoPublishedProductEditor> getRequiredType() {5		return DemoPublishedProductEditor.class;6	}7
8	@Override9	public void convert(10			@NonNull PublishedCatalogEntity catalogEntity,11			@NonNull DemoPublishedProductEditor entity,12			@NonNull AbstractEvitaJobContext context13	) {14		entity.setDemoNumber(catalogEntity.getStringData(ATTRIBUTE_DEMO_NUMBER));15	}16}

Zkopírovat odkaz na sekci4. Přidání do systému

Nakonec je potřeba servisu DemoPublishedProductService a snippet DemoPublishedProductConversionSnippet zavést do EdeeShop modulu. Zavedení je možné provést v rámci projektového rozšíření (feature). Popis jak vytvořit projektové rozšíření je zde.

java
1 @Override2    public void beforeSpringInitialization() {3        super.beforeSpringInitialization();4
5        if (isFeatureEnabled()) {6                final EntityModelClassConfiguration entityModel = getFeature(CatalogFeature.class).getEntityModelClassConfiguration();7        8                // register extension for source data9                entityModel.getModelDescriptor(PRODUCT).addTrait(WithDemoNumber.class);10        11                // register conversion snippet and service-class for published data12                final EvitaPublishingService evitaPublishingService = getFeature(EvitaFeature.class)13                        .getEvitaPublishingService();14        15                evitaPublishingService.getPublishingDescriptorFor(PRODUCT)16                        .addEvitaConversionSnippet(new DemoPublishedProductConversionSnippet())17                        .registerPublishedServiceClass(DemoPublishedProductService.class);18            }19        }20
21    // Projektové rozšíření se musí vykonat, až po rozšíření dané entity. 	22    @Override23    public FeatureDependency[] getRequiredFeatures() {24            return new FeatureDependency[]{25                new FeatureDependency(ProductFeature.class, true)26            };27    }

Zkopírovat odkaz na sekci5. Použití

Následně všechny načtené produkty budou obsahovat i atribut demoNumber, který bude možné filtrovat a řadit.

Zkopírovat odkaz na sekci5.1 Traity na přání

Pokud budete potřebovat na konkrétním místě v konkrétní situaci dynamicky doplnit nějaký další trait, je možné využít tzv. traity na přání.

Mějme například trait CustomTrait s jedním atributem data.

java
1 @Trait2public interface CustomTrait extends LocalDataStore {3
4    default void setData(Integer data) {5        setLocalData("data", data);6    }7
8    default Integer getData() {9        return getLocalData("data");10    }11
12}

Následně je možné si náš demo produkt "přebalit" do nové třídy, která bude mít navíc i tento trait.

java
1 // vytvoříme si nějaký produkt a necháme jej vypublikovat2runAndPublish(() -> {3	testDataGenerator.createProduct(4			new TestDataRequestProduct(TEST_CATALOG_CODE, "p1")5					.generateDefaultPrice()6	);7});8// načteme si vypublikovanou verzi produktu9DemoPublishedProduct product = publishedProductService.getProductByQuery(10		new ProductQuery(TEST_CATALOG_CODE).withCodes("p1")11).orElseThrow();12
13final DemoPublishedProduct onDemandExtendedProduct = publishedProductService.wrapInto(product, CustomTrait.class);14assertTrue(wrappedProduct instanceof CustomTrait);15((CustomTrait)wrappedProduct).setData(42);16assertEquals(Integer.valueOf(42), ((CustomTrait)wrappedProduct).getData());17
18assertEquals("p1", wrappedProduct.getCode());

Tato funkcionalita dává smysl ve chvílích, kdy nechcete změnit rozhraní produktu v celém systému, ale jen v nějaké konkrétní situaci - například pro vykreslení jedné konkrétní stránky, výstup v rámci jednoho konkrétního služby (controller), či ve spojení s nějakým konkrétním kontextem (např. kontextem přihlášeného uživatele), který je dostupný jen v určitém místě aplikace.