How to create a Drupal 8 view programmatically - drupal

I am trying to create a view programmatically in Drupal 8. Something similar to the crud log module in Drupal 7. I couldn't find any references on the internet either.

I was successful in creating a view programatically----I did the following--
1. Create a folder--C:\xampp\htdocs\Drupal Instance\modules
2. Create a YML info file --first_view.info and add the following code to it----
name: First View
type: module
description: My First Drupal 8 View
package: Custom
core: 8.x
3. Create an install file---first_view.install
And add the following code to it
<?php
/**
* #file
* Install, schema, and uninstall functions for the First View module.
*/
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\taxonomy\Entity\Term;
/**
* Implements hook_install().
*/
function first_view_install() {
}
/**
* Implements hook_uninstall().
*/
function first_view_uninstall() {
}
/**
* Implements hook_schema().
*/
function first_view_schema() {
$schema['first_view_table'] = [
// Example (partial) specification for table "node".
'description' => 'The base table for first_view.',
'fields' => [
'id' => [
'description' => 'The primary identifier for a node.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
],
'name' => [
'description' => 'The name of Employee.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
],
'age' => [
'description' => 'The age of employee.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
],
'is_active' => [
'description' => 'The activity of employee.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
],
'timestamp' => [
'description' => 'The timestamp of employee.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
],
'project_code' => [
'description' => 'The project code of employee.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => 0,
],
],
'unique keys' => [
'id' => ['id'],
],
// For documentation purposes only; foreign keys are not created in the
// database.
'primary key' => ['id'],
];
return $schema;
}
4. Create a file---first_view.views.inc
And add the following code to it--
<?php
/**
* Implements hook_views_data().
*/
function first_view_views_data() {
$data = [];
$data['first_view_table'] = [];
$data['first_view_table']['table'] = [];
$data['first_view_table']['table']['group'] = t('First View table');
$data['first_view_table']['table']['provider'] = 'first_view_module';
$data['first_view_table']['table']['base'] = [
'field' => 'id',
'title' => t('First View table'),
'help' => t('First View table contains example content and can be related to nodes.'),
'weight' => -10,
];
$data['first_view']['table']['join'] = [
'node_field_data' => [
'left_field' => 'id',
'field' => 'id',
'extra' => [
0 => [
'field' => 'published',
'value' => TRUE,
],
1 => [
'left_field' => 'age',
'value' => 1,
'numeric' => TRUE,
],
2 => [
'field' => 'published',
'left_field' => 'is_active',
'operator' => '!=',
],
],
],
];
$data['first_view_table']['table']['join']['node_field_data'] = [
'left_table' => 'foo',
'left_field' => 'id',
'field' => 'id',
'extra' => [
['left_field' => 'project_code', 'field' => 'project_code'],
['field' => 'age', 'value' => 0, 'numeric' => TRUE, 'operator' => '>'],
],
];
$data['first_view_table']['id'] = [
'title' => t('Example content'),
'help' => t('Relate example content to the node content'),
'relationship' => [
'base' => 'node_field_data',
'base field' => 'id',
'id' => 'standard',
'label' => t('Example node'),
],
];
$data['first_view_table']['name'] = [
'title' => t('Name'),
'help' => t('Just a Name field.'),
'field' => [
'id' => 'standard',
],
'sort' => [
'id' => 'standard',
],
'filter' => [
'id' => 'string',
],
'argument' => [
'id' => 'string',
],
];
$data['first_view_table']['project_code'] = [
'title' => t('Project Code'),
'help' => t('Just a Project code field.'),
'field' => [
'id' => 'standard',
],
'sort' => [
'id' => 'standard',
],
'filter' => [
'id' => 'string',
],
'argument' => [
'id' => 'string',
],
];
$data['first_view_table']['age'] = [
'title' => t('Age'),
'help' => t('Just a numeric field.'),
'field' => [
'id' => 'numeric',
],
'sort' => [
'id' => 'standard',
],
'filter' => [
'id' => 'numeric',
],
'argument' => [
'id' => 'numeric',
],
];
$data['first_view_table']['is_active'] = [
'title' => t('Is Active'),
'help' => t('Just an on/off field.'),
'field' => [
'id' => 'boolean',
],
'sort' => [
'id' => 'standard',
],
'filter' => [
'id' => 'boolean',
'label' => t('Published'),
'type' => 'yes-no',
'use_equal' => TRUE,
],
];
$data['first_view_table']['timestamp'] = [
'title' => t('Timestamp'),
'help' => t('Just a timestamp field.'),
'field' => [
'id' => 'date',
],
'sort' => [
'id' => 'date',
],
'filter' => [
'id' => 'date',
],
];
$data['views']['area'] = [
'title' => t('Text area'),
'help' => t('Provide markup text for the area.'),
'area' => [
'id' => 'text',
],
];
return $data;
}
By following the above steps....when we install and enable the module a table gets created in the database...You will have to populate it in order to see some data in the view...don't forget to add dummy data in the table.....After that go to Structure/views--- And click on "Add View"----Give a name to your View---and then you will be able to see the table name in "Show" Drop Down box---In this case the table name is "First View Table"...I hope this article would be helpful....

Although it is not created from scratch programatically, here is a simple method:
create a view using the back office
export that single view using the configuration manager module
copy that yml file and place it in a basic custom module /config/install folder
remove the first line containing the uuid
(optional )modify the file manually if needed and if understood how it work
activating your custom module will import the view

You can create a new View through the ConfigEntityStorage.
Create the View in the UI. Export the View's YAML config file to a path in your module, removing the UUID.
// view config is in `my_module/config/install/views.view.my_view.yml`
// (uuid removed!)
$dir = drupal_get_path('module', 'my_module');
$fileStorage = new FileStorage($dir);
$config = $fileStorage->read('views.view.my_view');
/** #var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
$storage = \Drupal::entityTypeManager()
->getStorage('view');
/** #var \Drupal\views\Entity\View $view */
$view = $storage->create($config);
$view->save();

Related

Symfony 5 - display an required input field after a specify dropdown select

I would like to build a form with Symfony 5 that should display a required input field for a certain dropdown selection.
After selecting "sonstiges" I need a required input field.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('salutation', ChoiceType::class, [
'label' => 'salutation',
'required' => true,
'constraints' => [
new NotBlank()
],
'placeholder' => 'Bitte wählen',
'label_attr' => [
'class' => 'visually-hidden'
],
'choices' => [
'Herr' => 'herr',
'Frau' => 'frau',
'Diverse' => 'diverse',
],
])
->add('firstname', TextType::class, [
'label' => false,
'required' => true,
'constraints' => [
new NotBlank()
],
'attr' => [
'placeholder' => "firstname",
],
])
->add('afterWork', ChoiceType::class, [
'label' => 'afterWork',
'required' => true,
'constraints' => [
new NotBlank()
],
'placeholder' => 'Bitte wählen',
'label_attr' => [
'class' => 'visually-hidden'
],
'choices' => [
'Studium' => 'studium',
'weitere Schule' => 'weiterSchule',
'Ausbildung' => 'ausbildung',
'Sonstiges' => 'sonstiges',
],
])
}
I added a $builder->addEventListener, unfortunately it didn't give me the result I need, I also added the input field as not required, hidden it and displayed it with a javascript. Unfortunately, it will not be validated because it is not required in the $builder.
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) {
$form = $event->getForm();
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
if (!is_null($data) && $data['afterWork'] == "sonstiges") {
$form->add('afterWorkText', TextType::class, [
'label' => "afterWorkText",
'required' => false,
'constraints' => array(
new NotBlank(),
),
'attr' => [
'placeholder' => "afterWorkText"
],
'label_attr' => [
'class' => 'visually-hidden'
],
]);
}
}
Is there a way to insert this field with "display:none" attribute and activate it with a javascript? In addition, the field should then be set to required.
Or can someone help me to find the right solution here?

Elementor access settings inside _register_controls function

I am using Elementor. In one section user can create categories with repeater field. In other section I would like to list these categories in Select2 control. How could I access category_data in _register_controls function? I know I can access it in render function.
protected function _register_controls() {
$this->start_controls_section(
'content_section',
[
'label' => __( 'Content', 'plugin-name' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
$repeater->add_control(
'category_title', [
'label' => esc_html__( 'Title', 'plugin-name'),
'type' => \Elementor\Controls_Manager::TEXT,
'label_block' => false,
]
);
$repeater->add_control(
'category_slug', [
'label' => esc_html__( 'Slug', 'plugin-name'),
'type' => \Elementor\Controls_Manager::TEXT,
'label_block' => false,
]
);
$this->add_control(
'category_data',
[
'label' => esc_html__( 'Category', 'plugin-name'),
'type' => \Elementor\Controls_Manager::REPEATER,
'fields' => $repeater->get_controls(),
'prevent_empty' => false,
'title_field' => '{{{ category_title }}}',
]
);
$this->end_controls_section();
$this->start_controls_section(
'category_section',
[
'label' => __( 'Category', 'plugin-name' ),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
//how could I access category_data here?
$settings = $this->get_settings_for_display();
$category_data = $settings['category_data'];
$cd_arr = [];
foreach ($category_data as $cd) {
$cd_arr[] = $cd['category_slug'];
}
if(count($cd_arr) > 0){
$this->add_control(
'media_category',
[
'label' => esc_html__( 'Categories', 'plugin-name'),
'type' => \Elementor\Controls_Manager::SELECT2,
'multiple' => true,
'options' => $cd_arr,
]
);
}
$this->end_controls_section();
}

API Platform - How to add response code in Swagger UI using decorator to add 400, 404, 500 response code so client know the response in adwance

I want to add Response code(400,404, 500) for each route in swagger UI using , so that user know in advance what will be the response for these error code.
I am following following link but not sure how can I modify the Response object and can add the response for 400, 404, 401 so on.
https://api-platform.com/docs/core/openapi/#overriding-the-openapi-specification
I am using symfony 5.2 and apiplatfrom 2.6 while writing this question.
When you are using decorators, you are essentially extending existing service code.
First you are getting path and then set your custom operation in swagger context with the given code.
If you notice the code block:
$openApi->getPaths()->addPath('/api/grumpy_pizzas/{id}', $pathItem->withGet(
$operation->withParameters(array_merge(
$operation->getParameters(),
[new Model\Parameter('fields', 'query', 'Fields to remove of the output')]
))
));
The path item take Operation object as an argument which has withResponses method that can be used to modify any responses that your path generates.
Take this as per-cursor and you can check whole source and see what fits your requirements best. Check source : PathItem.php
You can build response according to Response object and add it to Operation and to path.
Tip: Any editor with good linter would make your coding easier as it will be able to show you available methods.
Its late to post but I got the solutions for adding response code in my Swagger Ui, it can help some looking for solution.
private function setErrorResponseDescriptions(OpenApi $openApi): OpenApi
{
$schemas = $openApi->getComponents()->getSchemas();
$schemas['Error'] = [
'type' => 'object',
'properties' => [
'type' => [
'type' => 'string',
'readOnly' => true,
],
'title' => [
'type' => 'string',
'readOnly' => true,
],
'detail' => [
'type' => 'string',
'readOnly' => true,
],
],
];
$schemas['ValidationError'] = [
'type' => 'object',
'properties' => [
'type' => [
'type' => 'string',
'readOnly' => true,
],
'title' => [
'type' => 'string',
'readOnly' => true,
],
'detail' => [
'type' => 'string',
'readOnly' => true,
],
'validations' => [
'type' => 'array',
'readOnly' => true,
'items' => [
'type' => 'object',
'properties' => [
'propertyPath' => [
'type' => 'string',
'readOnly' => true,
],
'message' => [
'type' => 'string',
'readOnly' => true,
],
]
]
]
],
];
foreach ($openApi->getPaths()->getPaths() as $path => $pathItem) {
foreach (['PUT', 'POST', 'PATCH', 'GET'] as $method) {
$item = $pathItem->{'get' . ucfirst($method)}();
if ($item) {
$item->addResponse(
new Model\Response(
description: 'Unauthorized',
content: new \ArrayObject([
'application/problem+json' => [
'schema' => [
'$ref' => '#/components/schemas/Error',
],
],
])
),
'401'
);
if ('GET' !== $method) {
$item->addResponse(
new Model\Response(
description: 'Bad request',
content: new \ArrayObject([
'application/problem+json' => [
'schema' => [
'$ref' => '#/components/schemas/ValidationError',
],
],
])
),
'400'
);
} else {
$item->addResponse(
new Model\Response(
description: 'Not Found',
content: new \ArrayObject([
'application/problem+json' => [
'schema' => [
'$ref' => '#/components/schemas/Error',
],
],
])
),
'404'
);
}
}
}
}
return $openApi;
}

Sonata date picker month resets to 1

I use sonata_type_datetime_range_picker. I works correct on the frontend side. But when I submit form it remakes month value to 1. I.e. my submitted value is "2017-02-02 03:14:00" and value after submit is "2017-01-02 03:14:00". According to the profiler date is correct in the Request object but is wrong in Symfont Form Component.
My admin code
$datePickerOptions = [
'format' => "YYYY-MM-DD HH:mm:SS",
'datepicker_use_button' => false,
'dp_use_minutes' => false,
'dp_use_seconds' => false,
'dp_side_by_side' => true,
'dp_language' => 'en',
];
$datagridMapper
->add(
'dateTime',
'doctrine_orm_datetime_range',
[
'show_filter' => true,
'field_type' => 'sonata_type_datetime_range_picker',
'field_options' => [
'field_options_start' => $datePickerOptions,
'field_options_end' => $datePickerOptions,
],
]
);
What am I doing wrong?
Ok, I kinda found the working solution myself. Maybe it helps someone other sometime:
$now = new \DateTime();
$historyStart = new \DateTime('Dec 20 2016');
$dateFormat = 'd.m.y H';
$datagridMapper
->add(
'dateTime',
'doctrine_orm_datetime_range',
['show_filter' => true,],
'sonata_type_datetime_range_picker',
[
'field_options_start' => [
'dp_min_date' => $historyStart->format($dateFormat),
'dp_max_date' => $now->format($dateFormat),
'dp_default_date' => $now->format($dateFormat),
'dp_language' => 'en',
'format' => 'dd.MM.yy HH',
'datepicker_use_button' => false,
'dp_use_minutes' => false,
'dp_use_seconds' => false,
'dp_side_by_side' => true,
],
'field_options_end' => [
'dp_min_date' => $historyStart->format($dateFormat),
'dp_max_date' => $now->format($dateFormat),
'dp_default_date' => $now->format($dateFormat),
'dp_language' => 'en',
'format' => 'dd.MM.yy HH',
'datepicker_use_button' => false,
'dp_use_minutes' => false,
'dp_use_seconds' => false,
'dp_side_by_side' => true,
]
]
);

Cakephp 3.x Saving multiple tables

In my cakephp (3.3) project, How to save multiple tables in a single save. My association is as follows, also I am giving my code here.
Table1 : users
In class UsersTable extends Table
$this->hasOne('ProfileDetails', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
Table2 : profile_details
In class ProfileDetailsTable extends Table
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
What should be the data format to save multiple tables?
In my template I have added the following , for now I have used only few fields
$this->Form->input('User.username',['type' => 'text','class'=>'form-control']) ?>
$this->Form->input('User.password',['type' => 'password','class'=>'form-control']) ?>
$this->Form->input('User.email',['type' => 'text','class'=>'form-control']) ?>
$this->Form->input('ProfileDetail.first_name',['type' => 'text','class'=>'form-control']) ?>
In the controller before saving i have debuged which gives result as follows
debug($this->request->data);
$user = $this->Users->patchEntity($user, $this->request->data);
debug($user);
exit;
$this->Users->save($user)
Result of debug
\src\Controller\UsersController.php (line 39)
[
'User' => [
'username' => 'Tester',
'password' => '43434324',
'email' => 'test#gmail.com',
'role' => 'admin'
],
'ProfileDetail' => [
'first_name' => 'Tester'
]
]
\src\Controller\UsersController.php (line 41)
object(App\Model\Entity\User) {
'User' => [
'username' => 'Tester',
'password' => '43434324',
'email' => 'test#gmail.com',
'role' => 'admin'
],
'ProfileDetail' => [
'first_name' => 'Tester'
],
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'User' => true,
'ProfileDetail' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [
'email' => [
'_required' => 'This field is required'
]
],
'[invalid]' => [],
'[repository]' => 'Users'
}
Could you please suggest me how to save this data in multiple tables with single save with validation?
Looking at your debug, there is an error saying the email field is required. Maybe that is your problem..
If still not working , try this:
replace User by users
and ProjectDetail by project_details
In your form. And also remove joinType from following:
$this->hasOne('ProfileDetails', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);

Resources