Skip to content

Commit

Permalink
Add new dca author field mechanic (#69)
Browse files Browse the repository at this point in the history
* add new author field mechanic and deprecate DcaUtil::addAuthorFieldAndCallback()

* adjust readme
  • Loading branch information
koertho committed Oct 12, 2023
1 parent f53c759 commit 7bc382c
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 0 deletions.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ huh.utils.pdf.preview | `"spatie/pdf-to-image": "^1.8"` or/and `"alchemy/ghostsc

## Usage

### Utils

> We're currently in a process moving all services into the Utils namespace and make them all accessible from a new Utils service.
This Bundle is a collection of utils to solve recurring tasks. See the [API Documentation](https://heimrichhannot.github.io/contao-utils-bundle/) to see all util-classes and -methods.
Expand Down Expand Up @@ -98,6 +100,37 @@ huh.utils.url
huh.utils.user
```

### Common dca fields

The bundle provides some common dca fields that can be used in your dca files.

#### Author field

Add an author field to your dca. It will be initialized with the current backend user. On copy, it will be set to the current user.

```php
# contao/dca/tl_example.php
use HeimrichHannot\UtilsBundle\Dca\AuthorField;

AuthorField::register('tl_example');
```

You can pass additional options to adjust the field:

```php
# contao/dca/tl_example.php
use HeimrichHannot\UtilsBundle\Dca\AuthorField;

AuthorField::register('tl_example', [
'type' => AuthorField::TYPE_USER, // can be change to TYPE_MEMBER to set a frontend member instead of a backend user
'fieldNamePrefix' => '', // custom prefix for the field name
'useDefaultLabel' => true, // set to false to disable the default label and set a custom label in your dca translations
'exclude' => true,
'search' => true,
'filter' => true,
]);
```

## Documentation

[API Documentation](https://heimrichhannot.github.io/contao-utils-bundle/)
Expand Down
35 changes: 35 additions & 0 deletions src/Dca/AuthorField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace HeimrichHannot\UtilsBundle\Dca;

class AuthorField
{
public const TYPE_USER = 'user';
public const TYPE_MEMBER = 'member';

protected static array $tables = [];

/**
* Register a dca to have an author field and update logic added.
*
* @param string $table
* @param array{
* type?: string,
* fieldNamePrefix?: string,
* useDefaultLabel?: bool,
* exclude?: bool,
* search?: bool,
* filter?: bool,
* } $options
* @return void
*/
public static function register(string $table, array $options = []): void
{
static::$tables[$table] = $options;
}

public static function getRegistrations(): array
{
return static::$tables;
}
}
3 changes: 3 additions & 0 deletions src/Dca/DcaUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,9 @@ public function generateAlias(?string $alias, int $id, ?string $table, string $t
return $alias;
}

/**
* @deprecated Use AuthorField::register() instead
*/
public function addAuthorFieldAndCallback(string $table, string $fieldPrefix = '')
{
$this->framework->getAdapter(Controller::class)->loadDataContainer($table);
Expand Down
111 changes: 111 additions & 0 deletions src/EventListener/DcaAuthorListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

namespace HeimrichHannot\UtilsBundle\EventListener;

use Contao\BackendUser;
use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\CoreBundle\ServiceAnnotation\Hook;
use Contao\DataContainer;
use Contao\FrontendUser;
use Contao\Model;
use HeimrichHannot\UtilsBundle\Dca\AuthorField;
use Symfony\Component\Security\Core\Security;

class DcaAuthorListener
{
private ContaoFramework $framework;
private Security $security;

public function __construct(ContaoFramework $framework, Security $security)
{
$this->framework = $framework;
$this->security = $security;
}


/**
* @Hook("loadDataContainer")
*/
public function onLoadDataContainer(string $table): void
{
if (!isset(AuthorField::getRegistrations()[$table])) {
return;
}

$options = $this->getOptions($table);

$authorFieldName = empty($options['fieldNamePrefix']) ? 'author' : $options['fieldNamePrefix'].'Author';

$authorField = [
'exclude' => $options['exclude'],
'search' => $options['search'],
'filter' => $options['filter'],
'inputType' => 'select',
'eval' => [
'doNotCopy' => true,
'mandatory' => true,
'chosen' => true,
'includeBlankOption' => true,
'tl_class' => 'w50'
],
'sql' => "int(10) unsigned NOT NULL default 0",
];

if ($options['useDefaultLabel']) {
$authorField['label'] = &$GLOBALS['TL_LANG']['MSC']['utilsBundle']['author'];
}

if (AuthorField::TYPE_USER === $options['type']) {
$authorField['default'] = BackendUser::getInstance()->id;
$authorField['foreignKey'] = 'tl_user.name';
$authorField['relation'] = ['type'=>'hasOne', 'load'=>'lazy'];
} elseif (AuthorField::TYPE_MEMBER === $options['type']) {
$authorField['default'] = FrontendUser::getInstance()->id;
$authorField['foreignKey'] = "tl_member.CONCAT(firstname,' ',lastname)";
$authorField['relation'] = ['type'=>'hasOne', 'load'=>'lazy'];
} else {
$authorField['default'] = 0;
}

$GLOBALS['TL_DCA'][$table]['fields'][$authorFieldName] = $authorField;
$GLOBALS['TL_DCA'][$table]['config']['oncopy_callback'][] = [self::class, 'onConfigCopyCallback'];
}


public function onConfigCopyCallback(int $insertId, DataContainer $dc): void
{
$options = $this->getOptions($dc->table);
$authorFieldName = empty($options['fieldNamePrefix']) ? 'author' : $options['fieldNamePrefix'].'Author';

/** @var class-string<Model> $modelClass */
$modelClass = $this->framework->getAdapter(Model::class)->getClassFromTable($dc->table);
$model = $modelClass::findByPk($insertId);
if (!$model) {
return;
}

if (AuthorField::TYPE_USER === $options['type']) {
$model->{$authorFieldName} = BackendUser::getInstance()->id;
} elseif (AuthorField::TYPE_MEMBER === $options['type']) {
$model->{$authorFieldName} = FrontendUser::getInstance()->id;
} else {
$model->{$authorFieldName} = 0;
}
}

/**
* @param string $table
* @return array|bool[]|string[]
*/
protected function getOptions(string $table): array
{
return array_merge([
'type' => AuthorField::TYPE_USER,
'fieldNamePrefix' => '',
'useDefaultLabel' => true,
'exclude' => true,
'search' => true,
'filter' => true,
], AuthorField::getRegistrations()[$table]);
}
}

0 comments on commit 7bc382c

Please sign in to comment.