Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Fieldtype + Configuration #2

Merged
merged 4 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Ibexa Icon Fieldtype
This bundle provides a new field type "icon".
It allows an editor to select an icon from a predefined set of icons

## Features
* Configure multiple icon-sets
* Select the icon-set at content-type edit level
* Select icon from a dropdown instead of text

## Installation
1. Add the bundle
```shell
composer require elbformat/icon-bundle
```

2. Activate the bundle
```php
Elbformat\IconBundle\ElbformatIconBundle::class => ['all' => true],
```

3. Add iconset configuration
Add `config/packages/elbformat_icon.yaml`
```yaml
elbformat_icon:
iconset1:
- clock
- house
iconset2:
folder: "vendor/ezsystems/ezplatform-admin-ui/src/bundle/Resources/public/img/icons"
```
See [configuration](doc/configuration.md) for more advanced examples

## Usage
Edit a content-type and add an "Icon" field. Select icon-set to use.
When editing the content, a dropdown with icons will be shown.
17 changes: 12 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "elbformat/ibexa-icon-fieldtype",
"description": "Field type to select an icon from a predefined set.",
"name": "elbformat/icon-bundle",
"description": "Ibexa fieldtype to select an icon from a predefined set.",
"type": "symfony-bundle",
"license": "MIT",
"keywords": [
Expand All @@ -17,12 +17,14 @@
],
"autoload": {
"psr-4": {
"Elbformat\\IbexaIconFieldtype\\": "src/"
"Elbformat\\IconBundle\\": "src/"
}
},
"require": {
"php": ">=8.1",
"ezsystems/ezplatform-core": "^2.3"
"php": "^8.1",
"ezsystems/ezplatform-core": "^2.3",
"ezsystems/ezplatform-admin-ui": "^2.3",
"symfony/finder": "^5.4|^6.4"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
Expand All @@ -36,5 +38,10 @@
"symfony/flex": true,
"ibexa/post-install": true
}
},
"extra": {
"platform": {
"php": "8.1"
}
}
}
7 changes: 7 additions & 0 deletions config/ezplatform.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ezplatform:
system:
default:
field_templates:
- { template: '@ElbformatIconFieldtype/icon_field.html.twig', priority: 0 }
fielddefinition_edit_templates:
- { template: '@ElbformatIconFieldtype/icon_field_type_definition.html.twig', priority: 0 }
29 changes: 29 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
services:
Elbformat\IbexaIconFieldtype\FieldType\Icon\Type:
arguments:
$serializer: '@eZ\Publish\SPI\FieldType\ValueSerializerInterface'
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
tags:
- { name: ezplatform.field_type, alias: icon }
- { name: ezplatform.field_type.form_mapper.value, fieldType: icon }
- { name: ezplatform.field_type.form_mapper.definition, fieldType: icon }

Elbformat\IbexaIconFieldtype\FieldType\Icon\SearchField:
class: '%ezpublish.fieldType.indexable.unindexed.class%'
tags:
- { name: ezplatform.field_type.indexable, alias: icon }

Elbformat\IbexaIconFieldtype\Form\Type\IconType:
arguments:
$iconSetManager: '@Elbformat\IbexaIconFieldtype\IconSet\IconSetManager'
tags:
- { name: form.type }
Elbformat\IbexaIconFieldtype\Form\Type\IconSettingsType:
arguments:
$iconSetManager: '@Elbformat\IbexaIconFieldtype\IconSet\IconSetManager'
tags:
- { name: form.type }

Elbformat\IbexaIconFieldtype\IconSet\IconSetManager:
arguments:
$configs: [] # Will be set from bundle config
24 changes: 24 additions & 0 deletions doc/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Configuration

To configure your icon sets, there are two options:
1. Fixed sets of icon names
2. A list of icons derived from a filesystem folder

## Fixed set
To configure a fixed set of icons (e.g. "myicons"), use the following config syntax
```yaml
elbformat_icon:
myicons:
- clock
- house
```

## From filesystem
You can specify a folder that is being scanned for files. Optionally you can add a pattern to ignore non-icon files.
This example will look into the public/assets/build/images/icons folder and scans for svg files.
```yaml
elbformat_icon:
myiconsfromfolder:
folder: '%webroot_dir%/assets/build/images/icons'
pattern: '*.svg'
```
32 changes: 32 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('elbformat_icon');

$treeBuilder->getRootNode()
->arrayPrototype() // Name of the set
->normalizeKeys(false)
->children()
->arrayNode('items') // Fix list
->requiresAtLeastOneElement()
->normalizeKeys(false)
->scalarPrototype()->end()
->end()
->scalarNode('folder')->end() // Path to look in
->scalarNode('pattern')->end() // Glob expression
->end()
->end()
;

return $treeBuilder;
}
}
42 changes: 42 additions & 0 deletions src/DependencyInjection/ElbformatIconExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle\DependencyInjection;

use Elbformat\IconBundle\IconSet\IconSetManager;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Yaml\Yaml;

class ElbformatIconExtension extends Extension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../../config/'));
$loader->load('services.yaml');

$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);

$definition = $container->getDefinition(IconSetManager::class);
$definition->setArgument('$configs', $config);
}

public function prepend(ContainerBuilder $container): void
{
// Add template for rendering
$configFile = __DIR__.'/../../config/ezplatform.yaml';
$config = Yaml::parse(file_get_contents($configFile));
$container->prependExtensionConfig('ezpublish', $config['ezplatform']);

// Register namespace (as this is not done automatically. Maybe the missing "bundle" in path?)
$container->prependExtensionConfig('twig', ['paths' => [__DIR__.'/../../templates' => 'ElbformatIconFieldtype']]);

// Register translations (as this is not done automatically. Maybe the missing "bundle" in path?)
$container->prependExtensionConfig('framework', ['translator' => ['paths' => [__DIR__.'/../../translations']]]);

}
}
11 changes: 11 additions & 0 deletions src/ElbformatIconBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class ElbformatIconBundle extends Bundle
{

}
49 changes: 49 additions & 0 deletions src/FieldType/Icon/Type.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle\FieldType\Icon;

use Elbformat\IconBundle\Form\Type\IconSettingsType;
use Elbformat\IconBundle\Form\Type\IconType;
use eZ\Publish\SPI\FieldType\Generic\Type as GenericType;
use EzSystems\EzPlatformAdminUi\FieldType\FieldDefinitionFormMapperInterface;
use EzSystems\EzPlatformAdminUi\Form\Data\FieldDefinitionData;
use EzSystems\EzPlatformContentForms\Data\Content\FieldData;
use EzSystems\EzPlatformContentForms\FieldType\FieldValueFormMapperInterface;
use Symfony\Component\Form\FormInterface;

final class Type extends GenericType implements FieldValueFormMapperInterface, FieldDefinitionFormMapperInterface
{
public function getFieldTypeIdentifier(): string
{
return 'icon';
}

public function mapFieldValueForm(FormInterface $fieldForm, FieldData $data): void
{
$definition = $data->fieldDefinition;
$iconSet = $definition->getFieldSettings()['iconset'];
$fieldForm->add('value', IconType::class, [
'required' => $definition->isRequired,
'label' => $definition->getName(),
'icon_set' => $iconSet,
]);
}

public function getSettingsSchema(): array
{
return [
'iconset' => [
'type' => 'string',
'default' => '',
],
];
}

public function mapFieldDefinitionForm(FormInterface $fieldDefinitionForm, FieldDefinitionData $data): void
{
$fieldDefinitionForm->add('fieldSettings', IconSettingsType::class, [
'label' => false,
]);
}
}
28 changes: 28 additions & 0 deletions src/FieldType/Icon/Value.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle\FieldType\Icon;

use eZ\Publish\SPI\FieldType\Value as ValueInterface;

final class Value implements ValueInterface
{
private ?string $icon;

public function __construct(?string $icon=null) { $this->icon = $icon; }

public function __toString(): string
{
return $this->icon;
}

public function getIcon(): ?string
{
return $this->icon;
}

public function setIcon(?string $icon): void
{
$this->icon = $icon;
}
}
23 changes: 23 additions & 0 deletions src/Form/Type/IconSettingsType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle\Form\Type;

use Elbformat\IconBundle\IconSet\IconSetManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;

final class IconSettingsType extends AbstractType
{
public function __construct(
private readonly IconSetManager $iconSetManager,
) { }

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('iconset', ChoiceType::class,[
'choices' => $this->iconSetManager->getSetList()
]);
}
}
36 changes: 36 additions & 0 deletions src/Form/Type/IconType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle\Form\Type;

use Elbformat\IconBundle\FieldType\Icon\Value;
use Elbformat\IconBundle\IconSet\IconSetManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class IconType extends AbstractType
{
public function __construct(
private readonly IconSetManager $iconSetManager,
) { }


public function buildForm(FormBuilderInterface $builder, array $options): void
{
$iconSet = $options['icon_set'];
$builder->add('icon', ChoiceType::class,[
'choices' => $this->iconSetManager->getSet($iconSet)->getList()
]);
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Value::class,
'icon_set' => null,
]);
$resolver->addAllowedTypes('icon_set','string');
}
}
24 changes: 24 additions & 0 deletions src/IconSet/IconSet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);

namespace Elbformat\IconBundle\IconSet;

class IconSet
{
/** @var array<string,string> */
protected array $items;

/** @param string[] */
public function __construct(array $items)
{
// Convert to string => string array
$this->items = array_flip($items);
array_walk($this->items, fn(&$val, $key) => $val = $key);
}

/** @return string[] */
public function getList(): array
{
return $this->items;
}
}
Loading