How to programmatically query the translated content of a block in drupal9 - drupal

I created a block, the default language is English and the translation language is Chinese. Now I query the content of this block in my code:
$block = \Drupal::entityTypeManager()->getStorage('block_content')
->loadByProperties([
'info' => $info,
'langcode' => 'zh-hant'
]);
But what I got is still in English, what am I doing wrong?

You have to load the block_content entities without langcode condition, then get the translation in the language you need by getTranslation():
$blocks = \Drupal::entityTypeManager()->getStorage('block_content')
->loadByProperties([
'info' => $info
]);
$translated_blocks = array_map(function ($block) {
return $block->getTranslation('zh-hant');
}, $blocks);
// do somthing with $translated_blocks

Related

Use the category node name as a label in Zikula

I do use Zikula 1.5.2dev
My module is generated with modulestudio
I have made two entries in the Category registry. One is showing at the node "Global" and one at the node "Type"
In Global are several entries I can select. Some other entries are inside Type.
The selection is working in my template like expected. But how can I use the node names as a label?
I can not figure out in which template I have to place to label (have to do more searching). But more important, I do not know the right twig syntax to catch the categories label.
if you assign a category to the template, the properties are accessible like normal class properties.
{{ category.name }}
if you need the display name, this is stored as an array with lang codes as keys
{{ category.display_name['de'] }}
Hope that helps.
That sounds good. But now I have recognized this label seem not to be placed in a pure template. There is a form type defined:
class ShowRoomItemType extends AbstractShowRoomItemType
{
/**
* #inheritDoc
*/
public function addCategoriesField(FormBuilderInterface $builder, array $options)
{
$builder->add('categories', CategoriesType::class, [
'label' => $this->__('Category') . ':',
'empty_data' => null,
'attr' => [
'class' => 'category-selector'
],
'required' => false,
'multiple' => false,
'module' => 'RKShowRoomModule',
'entity' => 'ShowRoomItemEntity',
'entityCategoryClass' => 'RK\ShowRoomModule\Entity\ShowRoomItemCategoryEntity',
// added:
'includeGrandChildren' => true
]);
}
}
In my template it is called like this:
{{ form_row(quickNavForm.categories) }}
For this my skills are very limmited. I will write a feature request at modulestudio. (https://github.com/Guite/MostGenerator/issues/1147)
But big thanks for your reply!
This has been fixed for core 1.5.4 / 2.0.4 in https://github.com/zikula/core/pull/3846

Drupal 8 translating paragraphs programmatically

Paragraphs are supposed to be translated on on the level of their component fields, not on the paragraph_field level. So how do you programmatically translate paragraphs?
To be more explicit, my paragraph field is not translatable, but the component fields are. So how can I load a node, loop through the paragraph items, and add translations to the fields?
Does anyone have an example?
Thanks.
following https://www.flocondetoile.fr/blog/translate-programmatically-drupal-8 node translation:
This is an abstraction of my actual code, and I haven't actually tested it:
$node = node_load(12);
if ($node->hasTranslation('de')) {
$transl_node = $node->getTranslation('de');
foreach ($transl_node->field_paragraph => $paragraph) {
$entity_array = $paragraph->toArray();
$translated_fields = [];
$translated_fields['field_body'] = array(
'value' => 'translated value',
'format' => 'full'
);
$translated_fields['field_section_title'] = 'translated section title';
$translated_entity_array = array_merge($entity_array, $translated_fields);
if (!$paragraph->hasTranslation('de')) {
$paragraph->addTranslation('de', $translated_entity_array);
$paragraph->save();
}
}
$transl_node->save();
}

Symfony2 dynamically assign attr to form field

I'm in a situation where I want to be able to dynamically set the required=true/false option or the array(...other stuff..., 'class' => ' hidden') of a form field.
The context is the following: there is a "Project" entity with some fields. When I create other entities with forms I want to check some attributes of the Project entity and make decisions on the visibility/requiredness of certain fields of the entity I'm creating.
For example if a Project is with attribute "timePressure=high" then a field of a given entity is not required (but is visible). If there are other conditions it becomes invisible etc...
So basically I was hoping to call a function inside each ->add() of the form builder to spit out the relevant portions (e.g. that function would return a string with "required=true" or the other related to the hidden class). The thing is that the function should take as arguments: the projectID (ok, this can be passed as options of the form builder), the class and the field we are talking about to decide. I was envisioning something like:
->add('background', 'textarea', array('attr' => array('rows' => 4, functionToDecideIfInvisible($projectId)), functionToDecideRequiredness($projectId)))
The two function would return the string 'class' => ' hidden' and required=true (or false)
I'd like to avoid to having to specify the field name (in this case background) to avoid code repetition.
Can this be done?
Other suggestions on how to solve the thing?
Thank you!
SN
What you need are Form Events: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-underlying-data
They allow you to modify your form based on your data.
You create you project form in the controller:
$form = $this->createForm(new ProjectType(), $project, array(
'action' => $this->generateUrl('project.edit'),
'method' => 'POST',
));
Then you add the FormEvents::PRE_SET_DATA listener:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$project = $event->getData();
$form = $event->getForm();
// check timePressure on the Project object
if ('high' === $project->timePressure) {
$form->add('timePressure', 'text', array(
'required' => false
);
}
});
}
I found a way to do it.
My add would be like:
->add('background', 'textarea', array_merge($this->vr->fieldReq(get_class($this),
'background', $projectID), array('attr' => array_merge(array('rows' => 4, ),
$this->vr->fieldCssClass(get_class($this), 'background', $projectID) ) )))
To do that I had to define the form as service, plus I created another class as service (the one which holds the two methods I need).
This is the class:
class FieldReqAndCssClass
{
public function fieldReq($parentEntity, $field, $projectID)
{
$required = array();
$required['required'] = false; //do stuff on the database instead of setting it to false hardcoded
return $required;
}
public function fieldCssClass($parentEntity, $field, $projectID)
{
$cssClass= array();
//do stuff on the database instead of setting the class as hidden hardcoded
//$cssClass['class'] = ' hidden';
$cssClass['class'] = '';
return $cssClass;
}
}
Of course in my form I had to:
public function __construct(\AppBundle\Util\FieldReqAndCssClass $fieldReqAndCssClass)
{
$this->vr = $fieldReqAndCssClass; // vr stands for visibility and requiredness
}
And these are the two services:
app_bundle.field_req_and_css_class:
class: AppBundle\Util\FieldReqAndCssClass
arguments: []
app_bundle.form.type.projectdetail:
class: AppBundle\Form\Type\ProjectDetailFormType
arguments: [#app_bundle.field_req_and_css_class]
tags:
- { name: form.type, alias: ProjectDetail }
Of course here in the first service I'll need to inject the entity manager and add it to the construct, and probably also in the form service, but the basic skeleton is working :)
I'm a happy man :)
EDIT
The only problem of the above is that it makes hidden the widget but not the label. To fix it:
->add('background', 'textarea', array_merge($vr->fieldReq($myClass,
'background', $project), array('label_attr' => $vr->fieldCssClass($myClass,
'background', $project),'attr' => array_merge(array('rows' => 4, ),
$vr->fieldCssClass($myClass, 'background', $project) ) )))
Obviously before I have to declare:
$myClass = get_class($this);
$vr = $this->vr;

Render form without value in Symfony2

I'm building a form which have default value in some fields:
$builder->add('field', 'text', array('data' => 'Default value');
Then render this form field in Twig like:
{{ form_widget(form.field) }}
It's worked OK, but I don't want 'Default value' set in input tag rendered in HTML, because I only want this default value set internal that End-user doesn't aware about this value. Is there any built-in method in Symfony2 to handle it or I have to make some custom code?
You could modify your entity in order to do this:
class MyEntity{
const DEFAULT_FOO = "Default value";
// ...
private $foo;
// ...
public function setFoo($foo){
if ( $foo === null ){
$foo = self::DEFAULT_FOO;
}
$this->foo = $foo;
}
// ...
}
And then make sure that you set by_reference in order to ensure setter is being invoked each time:
$builder->add('field', 'text', array(
'by_reference' => true
));
As far i understand
try to add required false and handle it in your controller action.
$builder->add('field', 'text', array('required' => false));

Drupal Hook_Block_View perform action on button click

I am learning drupal and am trying to add some extra features to a module I've made following a tutorial
I have one block 'History' which shows the last x pages you've viewed.
Now I've made a second block with a button 'clear history', but I can't figure out how to make the set_value('trails_block_history','0') happen when my button is clicked (which would clear my history in the database)
anybody who can help me out here?
My blocks:
function trails_block_info() {
$blocks['history'] = array(
'info' => t('History'),
'cache' => DRUPAL_NO_CACHE,
);
$blocks['clearHist'] = array(
'info' => t('Clear history'),
'cache' => DRUPAL_NO_CACHE
);
return $blocks;
}
hook block save:
function trails_block_save($delta = '', $edit = array()) {
variable_set('trails_block_num', $edit['trails_block_num']);
variable_set('trails_block_granularity',$edit['trails_block_granularity']);
}
and the problem:
function trails_block_view($delta = '') {
...
case 'clearHist' :
{
$block['subject'] = 'Clear History';
$block['content'] = '<button>clear history</button>';
} break;
...
Still a student and reaaally new to this (started the module-coding this morning) so sorry if this seems like a stupid question (which it most probably is) but I just can't find it..
Have made another extra feature on the module allready, so I want this one to work as well!
You should use Forms API to create a form with submit button. Then clear your history when form is submitted. More info here and some example code here

Resources