shyim
6/6/2019 - 3:05 PM

gistfile1.txt

---
layout: default
title: Content Types
github_link: developers-guide/content-types/index.md
indexed: true
menu_title: Content-Types
menu_order: 100
group: Developer Guides
subgroup: General Resources
---

The content types allows users to create own simple entities with a crud, own api and frontend controller.

## General

Content types can be created using a interface in the administration in "Settings" => "Content Types" or with a `contenttypes.xml` in the Resources folder of your Plugin. If a content-type is created using a plugin, it can't be modified in the administration. In this guide we will create a content-type using a plugin.


## Creating a content type

A plugin content type can be created with a `Resources/contenttypes.xml`. A xml file can contain multiple content types.

```xml
<?xml version="1.0" encoding="utf-8"?>
<contentTypes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:noNamespaceSchemaLocation="../../../../engine/Shopware/Bundle/ContentTypeBundle/Resources/contenttypes.xsd">
    <types>
    </types>
</contentTypes>
```

Now add a content type in the types tag.

A content type needs as requirement a typeName (technical name, will be used for the controllers, table, etc. with the Prefix `Custom`), a name for the Menu and Storefront if enabled.

In this example we will create a content type with the technical name `myFancyContentType`, display name `My awesome content types` with an single field `name` as textfield.

```xml
<?xml version="1.0" encoding="utf-8"?>
<contentTypes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:noNamespaceSchemaLocation="../../../../engine/Shopware/Bundle/ContentTypeBundle/Resources/contenttypes.xsd">
    <types>
        <type>
            <typeName>myFancyContentType</typeName>
            <name>My awesome content types</name>
            <fieldSets>
                <fieldSet>
                    <field name="name" type="text">
                        <label>Name</label>
                        <showListing>true</showListing>
                    </field>
                </fieldSet>
            </fieldSets>
        </type>
    </types>
</contentTypes>
```

After the plugin installation and activation, will be a new menu in the `Content` section.

### Default elements

| Name          | DBAL Type | ExtJs Type                                 |
|---------------|-----------|--------------------------------------------|
| textarea      | text      | Ext.form.field.TextArea                    |
| text          | string    | Ext.form.field.Text                        |
| aceeditor     | text      | Shopware.form.field.AceEditor              |
| integer       | int       | Ext.form.field.Number                      |
| tinymce       | text      | Shopware.form.field.TinyMCE                |
| media         | int       | Shopware.form.field.Media                  |
| combobox      | string    | Ext.form.field.Combobox                    |
| checkbox      | int       | Ext.form.field.Checkbox                    |
| date          | date      | Ext.form.field.Date                        |
| media-grid    | string    | Shopware.form.field.MediaGrid              |
| product-field | int       | Shopware.form.field.ProductSingleSelection |
| product-grid  | string    | Shopware.form.field.ProductGrid            |
| shop-field    | int       | Shopware.form.field.SingleSelection        |
| shop-grid     | string    | Shopware.form.field.ShopGrid               |


### Dynamic elements

Content types can also reference each other. For this reason we have dynamic elements.

With `[technicalName]-field` can you create a association to a single selection of content type `technicalName`

With `[technicalName]-grid` can you create a association to a multi selection of content type `technicalName`

### Possible tags in the `<type>` tag

| Name                     | Description                                                                                                                             |
|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| typeName                 | technical name of the content type                                                                                                      |
| name                     | display name                                                                                                                            |
| showInFrontend           | create a frontend controller, allow usage of emotion element. Requires viewTitleFieldName, viewDescriptionFieldName, viewImageFieldName |
| menuIcon                 | menu icon                                                                                                                               |
| menuPosition             | menu position                                                                                                                           |
| menuParent               | parent controller name                                                                                                                  |
| viewTitleFieldName       | fieldname for title fields in storefront                                                                                                |
| viewDescriptionFieldName | fieldname for description fields in storefront                                                                                          |
| viewImageFieldName       | fieldname for image fields in storefront                                                                                                |
| seoUrlTemplate           | seo URL template for the url generation                                                                                                 |

### Possible tags in `<field>`

| Name          | Description                                                   |
|---------------|---------------------------------------------------------------|
| name          | technical fieldname in table                                  |
| label         | label for the user                                            |
| type          | field type                                                    |
| helpText      | field helpText                                                |
| description   | field description                                             |
| translateable | field is translateable?                                       |
| required      | field is required?                                            |
| options       | can be used to pass variables to extjs                        |
| custom        | can be used to store custom variables                         |
| store         | options for combobox selection                                |
| showListing   | show the field in the extjs listing window                    |
| searchAble    | field should be searchable in the extjs listing window search |

## Accesing using the API

All content types gets automaticly a generated api endpoint. It will be accessible with `/api/Custom[TechnicalName]` (e.g `/api/CustommyFancyContentType`) and follows the .

In default it reads the data in raw format, without resolving the assoicated data and translation.

To resolve the associations, can you pass a GET parameter `?resolve=1` and to load the translations, can you pass a GET parameter `?loadTranslations=1` to the list and get one call.

The passed data to create or update has to be in the raw format. Multi selection fields values has to been splitted by pipe (e.g `|1|2|`).

## Usage internal in PHP

### Getting content type configuration
The content type configuration will be saved as struct of type `Shopware\Bundle\ContentTypeBundle\Structs\Type`. To get the configuration of your content type you can use the service `shopware.bundle.content_type.type_provider` and call the method `getType` with your technical name.

### Fetching the content type data

Every content types gets a own Repository which implements the interface `Shopware\Bundle\ContentTypeBundle\Services\RepositoryInterface`. They are dynamicly registered in the di with following scheme `shopware.bundle.content_type.[technicalName]`.

#### Example usages

```php

/** @var \Shopware\Bundle\ContentTypeBundle\Services\RepositoryInterface $repository */
$repository = $this->container->get('shopware.bundle.content_type.store');

$criteria = new \Shopware\Bundle\ContentTypeBundle\Structs\Criteria();
$criteria->limit = 5;
$criteria->loadTranslations = true;
$criteria->loadAssociations = true;
$criteria->calculateTotal = true;

/** @var \Shopware\Bundle\ContentTypeBundle\Structs\SearchResult $result */
$result = $repository->findAll($criteria);

var_dump($result->total); // 5
var_dump($result->type); // Type struct
var_dump($result->items); // Fetched data


// Delete a record
$repository->delete($id);

// if a id is passed in $data, it will be updated, otherwise it will create a new record
$repository->save($data);
```

## Displaying in Frontend

To enable the frontend, you have to set `showInFrontend` in the `type` to `true` and fill the fields `viewTitleFieldName`, `viewDescriptionFieldName`, `viewImageFieldName`.

These view fields will be used for seo information in `<head>`, listing of the contents and in the emotion world.

The controller name is like in the api generated with the same schema `Custom[TechnicalName]`.
In default trys the controller to load the template in the default directory structure (frontend/controller/action.tpl), if that template is missing it fallbacks to the folder `frontend/content_type/action.tpl).

In the default template only fields are visible in the frontend, which implements the interface `Shopware\Bundle\ContentTypeBundle\Field\TemplateProvidingFieldInterface`

## Translation in Backend

To translate the extjs field names can you create a new snippet file in namespace `backend/custom[technicalName]/main`.

| Snippet-Name            | Description                              |
|-------------------------|------------------------------------------|
| name                    | content type name in backend             |
| [fieldName]_label       | field label for the frontend and backend |
| [fieldName]_helpText    | field helpText for the backend           |
| [fieldName]_description | field description for the backend        |

## Translation in Frontend

To translate the extjs field names can you create a new snippet file in namespace `frontend/custom[technicalName]/index`.

| Snippet-Name         | Description                  |
|----------------------|------------------------------|
| IndexMetaDescription | meta description in `<head>` |
| IndexMetaImage       | meta image  in `<head>`      |
| IndexMetaTitle       | meta title  in `<head>`      |

## Creating a new Field

To create a new field, you have to create a new class which implements the `Shopware\Bundle\ContentTypeBundle\Field\FieldInterface`.

Here we have a example field MediaField.

```php

use Doctrine\DBAL\Types\Type;
use Shopware\Bundle\ContentTypeBundle\Structs\Field;

class MediaField implements FieldInterface
{
    public static function getDbalType(): string
    {
        return Type::INTEGER;
    }

    public static function getExtjsField(): string
    {
        return 'shopware-media-field';
    }

    public static function getExtjsType(): string
    {
        return 'int';
    }

    public static function getExtjsOptions(Field $field): array
    {
        return [];
    }

    public static function isMultiple(): bool
    {
        return false;
    }
}
```

Overview of the methods

| Method          | Description                                            |
|-----------------|--------------------------------------------------------|
| getDbalType     | Returns the DBAL Type for the column                   |
| getExtjsField   | Returns the extjs xtype for the field                  |
| getExtjsType    | Returns the extjs model type                           |
| getExtjsOptions | Returns a array of options for the extjs configuration |
| isMultiple      | Returns that this field holds multiple values          |

After the creating of the class, we have to register our new Field in the `services.xml` with the tag `shopware.bundle.content_type.field` and a `fieldName`.

```xml
<service id="Shopware\Bundle\ContentTypeBundle\Field\MediaField" class="Shopware\Bundle\ContentTypeBundle\Field\MediaField">
    <tag name="shopware.bundle.content_type.field" fieldName="media"/>
</service>
```

The `fieldName` is the unique identifier of your new field and can be used in the `contenttypes.xml`. This also extends the selection in the extjs interface for the creation of a content type.

### ResolveableFieldInterface

If you want to populate the data after it has been read from the Database, can you implement to your field the interface `Shopware\Bundle\ContentTypeBundle\Field\ResolveableFieldInterface`.

This interface requires, that you have to implement the method getResolver. In the getResolver method have you to return a service id of your resolver. The resolver will handle the processing of the saved data.

```php
public static function getResolver(): string
{
    return MediaResolver::class;
}
```

### Resolver

A resolver has to extend `Shopware\Bundle\ContentTypeBundle\FieldResolver\AbstractResolver` and registered in the DI container. The abstract class requires that you implement the method `resolve`. The content types repository reads all informations from the database and then adds all fields that has to been resolved in the Resolver using the `add` method, defined in the `AbstractResolver`. After all ids added, it will call the `resolve()` method where the Resolver should fetch and store the data by the added ids.

Here we have a example for the `MediaField`

```php
public function resolve(): void
{
    $medias = $this->mediaService->getList($this->resolveIds, $this->contextService->getShopContext());

    foreach ($medias as $id => $media) {
        $this->storage[$id] = $this->structConverter->convertMediaStruct($media);
    }

    $this->resolveIds = [];
}
```

We have in the `resolveIds` property all requested ids of the values. After the fetching we write the data back into the `storage` property with the keys we had in `propertyIds`.
In the last step the Repository loads the values back from the `get` method implemented by the `AbstractResolver` with the values in the `storage` property.
This concept also has a simple cache inside, if the requested id is already in the `storage` proeprty, it won't be added to the `resolveIds` property.

### TemplateProvidingFieldInterface

With the `TemplateProvidingFieldInterface` interface can you mark your field as frontend ready with a specific template. This template will be loaded with the default template of the detail page.