TYPO3 - extending an extbase extension with new fields and using these in fluid templates - fluid

I'm trying to extend powermail (version 2) with the possibility to add a note for each input field. So far I have created a new extension using extension builder and with a few modifications to ext_tables.php the field show up in the backend. The new field is called 'note' and I thought I could just do something like {field.note} in the fluid template input.html, but that does not work. My model includes the setter and getter:
class Tx_Formnotes_Domain_Model_Powermailnotes extends Tx_Extbase_DomainObject_AbstractEntity {
/**
* note
*
* #var string
*/
protected $note;
/**
* Returns the note
*
* #return string $note
*/
public function getNote() {
return $this->note;
}
/**
* Sets the note
*
* #param string $note
* #return void
*/
public function setNote($note) {
$this->note = $note;
}
}
What else is needed?
Info: I'm using TYPO3 4.7

You could map the powermail model like
config.tx_extbase.persistence.classes {
Tx_Formnotes_Domain_Model_Powermailnotes {
mapping {
tableName = powermailTableName
columns {
exampleMedia.mapOnProperty = media
}
}
}
}
after that you should extend your TCA with these properties. At least you can write setter and getter for each property and use them in your fluid template.

Related

Why is the dynamic serialization group I've created not allowing a mutation for the specified property?

I've implemented a Dynamic Serialization group via Context Builder for admin users (adding admin:write). And have assigned this group to the property I want only updatable by an admin via GraphQL.
My implementation at this point is taken directly from https://api-platform.com/docs/core/graphql/#changing-the-serialization-context-dynamically
But when attempting to mutate this property I am given an error that reads Field "roles" is not defined by type updateUserInput.
This makes some sense to me as the schema does not contain this property since it is not in the typical write group. However, the documentation suggests this should be doable. If this is the case, what am I not doing correctly?
Relevant Code:
Context Builder
<?php
namespace App\Serializer;
use ApiPlatform\Core\GraphQl\Serializer\SerializerContextBuilderInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* Context Builder: Experimental implementation used for constructing what resources are returned.
*/
final class AdminGroupsContextBuilder implements SerializerContextBuilderInterface {
private $decorated;
private $authorizationChecker;
/**
*
*/
public function __construct(SerializerContextBuilderInterface $decorated, AuthorizationCheckerInterface $authorizationChecker) {
$this->decorated = $decorated;
$this->authorizationChecker = $authorizationChecker;
}
/**
*
*/
public function create(?string $resourceClass, string $operationName, array $resolverContext, bool $normalization): array {
$context = $this->decorated->create($resourceClass, $operationName, $resolverContext, $normalization);
$resourceClass = $context['resource_class'] ?? NULL;
if (isset($context['groups']) && $this->authorizationChecker->isGranted('ROLE_ADMIN') && FALSE === $normalization) {
$context['groups'][] = 'admin:input';
}
return $context;
}
}
User Entity Class property definition
/**
* #ORM\Column(type="json")
* #Groups({"read", "admin:write"})
*/
private $roles = [];
Services Definition
App\Serializer\AdminGroupsContextBuilder:
decorates: 'api_platform.graphql.serializer.context_builder'
arguments: [ '#App\Serializer\AdminGroupsContextBuilder.inner' ]
autoconfigure: false

EasyAdmin 3 Object of class DateTime could not be converted to string

I'm having a problem with easy admin 3.
I followed the instructions of the symfony doc but I end up with this error: Object of class DateTime could not be converted to string when rendering the admin.
Thank you for you help !
class ArticleCrudController extends AbstractCrudController
{
/**
* #return string
*/
public static function getEntityFqcn(): string
{
return Article::class;
}
/**
* #param Crud $crud
* #return Crud
*/
public function configureCrud(Crud $crud): Crud
{
return $crud
->setDateFormat('d/m/Y')
// ...
;
}
}
In your "Article" entity you have a DateTime property. You need to implement method
configureFields and return an DateTimeField. I don't know if it's the good way but it will fix your error.

Sylius - Editable Product Code (SKU)

I need to implement an SKU code for products, I was just wondering has anybody any thought on the best way to do this. The SKU needs to be editable after creation.
I feel I have a couple of ways:
(Idealy) I would like to use Product.Code, but this is not an editable field after product creation. I would seem I need to override the ProductType#buildForm class/method to not use AddCodeFormSubscriber(). Although I can't seem to figure out how to get the system to use a different form.
Add SKU to the model of Product and figure out how to add it to the ProductType form and again try and figure out how to use a different form.
I am open to suggestions on how to do it the right way.
Would any of the Sylius developers care to elaborate why they decided to make the Code field un-editable?
If you want use product code as editable field in Sylius Beta.1, you can create ProductType extension to current product type and add your custom subscriber which will make code field editable. I did this in my bundle and it works:
create subscriber class wchich will change disabled state to false:
namespace App\Bundle\Form\EventListener;
/* add required namespaces */
/**
* Custom code subscriber
*/
class CustomCodeFormSubscriber implements EventSubscriberInterface
{
private $type;
private $label;
/**
* #param string $type
* #param string $label
*/
public function __construct($type = TextType::class, $label = 'sylius.ui.code')
{
$this->type = $type;
$this->label = $label;
}
/**
* {#inheritdoc}
*/
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SET_DATA => 'preSetData',
];
}
/**
* #param FormEvent $event
*/
public function preSetData(FormEvent $event)
{
$disabled = false;
$form = $event->getForm();
$form->add('code', $this->type, ['label' => $this->label, 'disabled' => $disabled]);
}
}
create form extension and use custom subscriber:
namespace App\Bundle\Form\Extension;
use App\Bundle\Form\EventListener\CustomCodeFormSubscriber;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Sylius\Bundle\ProductBundle\Form\Type\ProductType;
/* use other required namespaces etc */
/**
* Extended Product form type
*/
class ProductTypeExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
/* custom stuff for ur form */
$builder->addEventSubscriber(new CustomCodeFormSubscriber());
}
public function getExtendedType()
{
return ProductType::class;
}
}
register your form extension as a service:
app.form.extension.type.product:
class: App\Bundle\Form\Extension\ProductTypeExtension
tags:
- { name: form.type_extension, priority: -1, extended_type: Sylius\Bundle\ProductBundle\Form\Type\ProductType }

How do I change default pagination attributes in Yii?

In my Yii project, I want the default pageSize for pagination to be fetched automatically, so I don't have to specify it in all the widgets that use pagination. But I can't seem to find a way to globally change the pagination class, without editing Yii source files. Is this possible?
Please create file on /components/WidgetFactory.php with below code.
<?php
/**
* Custom WidgetFactory class
* Provides two new events:
* - onBeforeCreateWidget
* - onAfterCreateWidget
*
* Allows for advanced global widget alteration, going a step further than CWidgetFactory's
* typical process which allows you to define default values for widgets.
*
*/
class WidgetFactory extends CWidgetFactory
{
/**
* Raised right BEFORE a widget is created.
* #param CEvent $event the event parameter
*/
public function onBeforeCreateWidget(CEvent $event)
{
$this->raiseEvent('onBeforeCreateWidget',$event);
}
/**
* Raised right AFTER a widget is created.
* #param CEvent $event the event parameter
*/
public function onAfterCreateWidget(CEvent $event)
{
$this->raiseEvent('onAfterCreateWidget',$event);
}
/**
* Creates a new widget based on the given class name and initial properties.
* #param CBaseController $owner the owner of the new widget
* #param string $className the class name of the widget. This can also be a path alias (e.g. system.web.widgets.COutputCache)
* #param array $properties the initial property values (name=>value) of the widget.
* #return CWidget the newly created widget whose properties have been initialized with the given values.
*/
public function createWidget($owner,$className,$properties=array())
{
if (! ($this->hasEventHandler('onBeforeCreateWidget') || $this->hasEventHandler('onAfterCreateWidget')))
return parent::createWidget($owner, $className, $properties);
$event=new WidgetEvent($this, $owner, $className, $properties);
if ($this->hasEventHandler('onBeforeCreateWidget'))
$this->raiseEvent('onBeforeCreateWidget', $event);
$event->widget=parent::createWidget($owner, $className, $properties);
if ($this->hasEventHandler('onAfterCreateWidget'))
$this->raiseEvent('onAfterCreateWidget', $event);
return $event->widget;
}
}
class WidgetEvent extends CEvent
{
/**
* #var CBaseController Owner of the new widget
*/
public $owner;
/**
* #var string Widget class name
*/
public $className;
/**
* #var CWidget The newly created widget
*/
public $widget;
/**
* Constructor.
* #param WidgetFactory $sender The WidgetFactory instance
* #param CBaseController $owner The owner of the new widget
* #param string $className The class name of the widget. This can also be a path alias.
* #param array $params The initial property values (name=>value) of the widget.
*/
public function __construct(WidgetFactory $sender, CBaseController $owner, $className, array $params=array())
{
parent::__construct($sender, $params);
$this->owner=$owner;
$this->className=$className;
}
}
And correct config/main.php like below.
return array(
// ...
'components'=>array(
// ...
'widgetFactory'=>array(
'class'=>'WidgetFactory',
'onAfterCreateWidget'=>function(WidgetEvent $event){
static $defaultPageSize=50; // YOUR_DEFAULT_PAGESIZE_HERE
$widget=$event->widget;
if ($widget instanceof CBaseListView) {
/** #var CBaseListView $widget */
if ($widget->dataProvider!==null && $widget->dataProvider->pagination!==false)
$widget->dataProvider->pagination->pageSize=$defaultPageSize;
}
},
),
// ...
),
);
Please notice default pageSize above on config code . I think it will solve your problem.

Adding custom data type (geometry) in Doctrine 2.1.7. Method canRequireSQLConversion() is not called

I am trying to add Geometry type to Doctrine. My Doctrine DBAL version and ORM versions are 2.1.7.
I tried to follow the instructions here:
Doctrine 2 Types - Custom Mapping Types.
I successfully created the new datatype, but I have problems with convertToPHPValueSQL method. I want function ST_AsText(' .. ') to always be called when getting the geometry column from database (database is PostgreSQL 9.1 + PostGIS 2.0.0).
Doctrine DBAL 2.1 documentation says like this:
The job of Doctrine-DBAL is to transform your type into SQL
declaration. You can modify the SQL declaration Doctrine will produce.
At first, you must to enable this feature by overriding the
canRequireSQLConversion method:
<?php
public function canRequireSQLConversion()
{
return true;
}
Then you override the methods convertToPhpValueSQL and
convertToDatabaseValueSQL :
<?php
public function convertToPHPValueSQL($sqlExpr, $platform)
{
return 'MyMoneyFunction(\''.$sqlExpr.'\') ';
}
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
{
return 'MyFunction('.$sqlExpr.')';
}
Now we have to register this type with the Doctrine Type system and
hook it into the database platform:
<?php
Type::addType('money', 'My\Project\Types\MoneyType');
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'money');
I did like this (lot of code is placeholder code, but if I did something stupid, all advice is welcome):
<?php
namespace Minupeenrad\Types;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Class for database column "geometry".
*
* #author Rauni Lillemets
*/
class GeometryType extends Type {
const GEOMETRY = 'geometry';
const SRID = 3301;
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform) {
return 'geometry';
}
//Should create WKT object from WKT string. (or leave as WKT string)
public function convertToPHPValue($value, AbstractPlatform $platform) {
return $value; //+
}
//Should create WKT string from WKT object. (or leave as WKT string)
public function convertToDatabaseValue($value, AbstractPlatform $platform) {
return $value; //+
}
public function getName() {
return self::GEOMETRY;
}
public function canRequireSQLConversion() {
return true;
}
//Should give WKT
public function convertToPHPValueSQL($sqlExpr, $platform) {
return 'ST_AsText(\''.$sqlExpr.'\') '; //+
}
//Should create WKB
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) {
return 'ST_GeomFromText(\''.$sqlExpr.'\', '.self::SRID.')'; //+
}
}
Now I added Entity that uses this column:
<?php
namespace Minupeenrad\Entities;
/**
* Field
*
* #author Rauni Lillemets
* #Entity
* #Table(name="myfields.fields")
*/
class Field extends GeometryObject {
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
private $id;
/**
* #ManyToOne(targetEntity="User")
*/
private $user;
/**
* #Column(type = "string", length = "40")
*/
private $fieldNumber;
public function getId() {
return $this->id;
}
public function getUser() {
return $this->user;
}
public function setUser($user) {
$this->user = $user;
}
public function getFieldNumber() {
return $this->fieldNumber;
}
public function setFieldNumber($fieldNumber) {
$this->fieldNumber = $fieldNumber;
}
}
?>
But if I do like this:
$entity = $em->find('\Minupeenrad\Entities\Field', 1);
Doctrine does SQL request to database like this:
SELECT t0.id AS id1, t0.fieldNumber AS fieldnumber2, t0.geometry AS geometry3, t0.user_id AS user_id4
FROM myfields.fields t0
WHERE t0.id = ?
Doctrine does not use my convertToPHPValueSQL method, although canRequireSQLConversion() returns true. Furthermore, I added some debug code to see if canRequireSQLConversion() is even called, and it is not called. What am I doing wrong?
PS: I tried to search Stack Overflow, but I only came up with GIS extension for Doctrine 2, which links to Doctrine 2.1.x manual that I already read.
EDIT: I will read here: http://docs.doctrine-project.org/en/latest/cookbook/advanced-field-value-conversion-using-custom-mapping-types.html
EDIT2: Fixed function getSqlDeclaration(), that was wrong in my code. Added comments.
It seems like a more complete tutorial.
Found the answer.
In Doctrine 2.1.7, if I used $em->find(), eventually BasicEntityPersister()_getSelectColumnSQL() was called. It has following code: (taken from https://github.com/doctrine/doctrine2/blob/2.1.x/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php)
/**
* Gets the SQL snippet of a qualified column name for the given field name.
*
* #param string $field The field name.
* #param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
* #param string $alias
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
return "$sql AS $columnAlias";
}
This code obviously does not respect method "canRequireSQLConversion"
In latest Doctrine version, 2.3.1 (see https://github.com/doctrine/doctrine2/blob/2.3/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php):
/**
* Gets the SQL snippet of a qualified column name for the given field name.
*
* #param string $field The field name.
* #param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
* #param string $alias
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
. '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
}
return $sql . ' AS ' . $columnAlias;
}
So the answer is to update my ORM.