Add values to 'config' table and 'key_value' table when creating a new field in an existing table in Drupal 8 - drupal

I'm new to drupal. I need to write a module that need to handle user related details.
I'm able to create the module and add the necessery database changes in 'users_field_data' table. by using db_add_field in hook_install()
db_add_field('users_field_data', 'user_office', array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
));
But one thing I noticed when installing some other module from drupal is when a new field is added to the database it saves some values to 'config' table and 'key_value'table.
Is there a way that I add the values to 'config' table and 'key_value' table when creating a new field in an existing table in drupal 8.

Adding fields to existing entities should be done using the field and field storage configuration entities.
Take the following steps to accomplish your goals:
Go to the manage fields page of the target entity (for user you can find the link in the configuration page)
Add the required field in the GUI.
Go to the configuration synchronization page and export the field and field storage configuration for the new field.
The new files should be saved in the config/install directory of your module.
Install the module
The field should be added on install.

Related

How do I query a Drupal Shortcut (8.x/9.x) by its URL or Menu Path?

We're rolling out an update to an in-house Drupal installation profile, and one of the menu paths that is used frequently is getting changed. Most of our installations reference that menu path in a shortcut (via the "Shortcut" module in core). In an update hook, we'd like to be able to query for those shortcuts and update them.
It feels like this should be straightforward, but for some reason we're finding it difficult to query for shortcuts by their url. We can query them by title, but that seems fragile (since the title could be different between installations, might be different by localization, etc.).
We tried the following, but this lead to the error message 'link' not found:
// This does NOT work.
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link' => [
'internal:/admin/timeline-management',
],
]);
// This works, but is fragile.
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'title' => 'My shortcut',
]);
Based on the code in \Drupal\shortcut\Entity\Shortcut::baseFieldDefinitions() and \Drupal\shortcut\Controller\ShortcutSetController::addShortcutLinkInline() it's obvious that Shortcut entities have a property called link that can be set like an array containing a uri key, yet it does not seem possible to query by this property even though it's a base field.
Looking at the database, it appears that Drupal stores the URL in a database column called link__uri:
TL;DR That means that this works:
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link__uri' => 'internal:/admin/old/path',
]
);
Read on if you want to know the subtle reason why this is the case.
Drupal's database layer uses pluggable "table mapping" objects to tell it how to map an entity (like a Shortcut) to one or more database tables and database table columns. The logic for generating a column name for a field looks like this in the default table mapping (\Drupal\Core\Entity\Sql\DefaultTableMapping):
As shown above, if a field indicates it allows "shared" table storage, and the field has multiple properties (uri, title, etc.), then the mapping flattens the field into distinct columns for each property, prefixed by the field name. So, a Shortcut entity with link => ['uri' => 'xyz']] becomes the column link__uri with a value of xyz in the database.
You don't see this often with entities like nodes, which is why this seems strange here. I'm usually accustomed to seeing a separate database table for things like link fields. That's because nodes and other content entities don't usually allow shared table storage for their fields.
How does the mapping determine if a field should use shared table storage? That logic looks like this:
So, the default table mapping will use shared table storage for a field only under specific circumstances:
The field can't have a custom storage handler (checks out here since shortcuts don't provide their own storage logic).
The field has to be a base field (shortcuts are nothing without a link, so that field is defined as a base field as mentioned in the OP).
The field has to be single-valued (checks out -- shortcuts have only one link).
The field must not have been deleted (checks out; again, what is a shortcut without a link field?).
This specific set of circumstances aren't often satisfied by nodes or other content entities, which is why it's a bit surprising here.
We can confirm this by using Devel PHP to ask the table mapping for shortcuts directly, with code like the following:
$shortcut_table_mapping =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->getTableMapping();
$efm = \Drupal::service('entity_field.manager');
$storage_definitions = $efm->getFieldStorageDefinitions('shortcut');
$link_storage_definition = $storage_definitions['link'];
$has_dedicated_storage = $shortcut_table_mapping->requiresDedicatedTableStorage($link_storage_definition);
$link_column = $shortcut_table_mapping->getFieldColumnName($link_storage_definition, 'url');
dpm($has_dedicated_storage, 'has_dedicated_storage(link)');
dpm($link_column, 'link_column');
This results in the following:

Viewing, adding and editing database content

I just started using Drupal and I was wondering if there is an easy way of viewing, adding or editing data from my custom database. Are there tutorials/modules which allow me to do these actions?
Sorry for the newbie question, I have no idea what to look for...
This question is perhaps more suitable for the Drupal Answers community.
Connecting a custom database
There is a great tutorial on how to connect Drupal to a separate, custom database, called How to connect to multiple databases within Drupal. In summary, it can be achieved by adding the following code into your settings.php file.
<?php
$databases = array();
$databases['default']['default'] = array(
// Drupal's database credentials go here
);
$databases['custom']['default'] = array(
// Custom database credentials go here
);
?>
Accessing custom database
First, tell Drupal that you're accessing a custom database, by inserting db_set_active('custom'); right before your query. To switch back to Drupal's default database, insert db_set_active();.
To make queries to your database, refer to a list of Database Functions. Although these functions are geared more towards a Drupal's default database, you'll find that certain functions will work on a custom database. For example, for simple SELECT queries, you may want to use the db_query.
db_query usage:
<?php
$uid = 1;
$result = db_query('SELECT n.nid, n.title, n.created
FROM {node} n WHERE n.uid = :uid', array(':uid' => $uid));
// Fetch next row as a stdClass object.
$record = $result->fetchObject();
// Fetch next row as an associative array.
$record = $result->fetchAssoc();
// Fetch data from specific column from next row
// Defaults to first column if not specified as argument
$data = $result->fetchColumn(1); // Grabs the title from the next row
// Retrieve a single value
$result->fetchField();
// Retrieve all records into an indexed array of stdClass objects.
$result->fetchAll();
// Retrieve all records as stdObjects into an associative array
// keyed by the field in the result specified.
// (in this example, the title of the node)
$result->fetchAllAssoc('title');
// Retrieve a 2-column result set as an associative array of field 1 => field 2.
$result->fetchAllKeyed();
// Also good to note that you can specify which two fields to use
// by specifying the column numbers for each field
$result->fetchAllKeyed(0,2); // would be nid => created
$result->fetchAllKeyed(1,0); // would be title => nid
// Retrieve a 1-column result set as one single array.
$result->fetchCol();
// Column number can be specified otherwise defaults to first column
$result->fetchCol($db_column_number);
// Count the number of rows
$result->rowCount();
?>
You were not clear if you need to merely manage the data, or edit the data in Drupal. If managing data is the need, use a front-end. Since you are using Drupal, you must be using PHP. If you are new to accessing databases, you may like to use PHPMyAdmin http://www.phpmyadmin.net. It may be already included with your PHP distribution if you installed PHP with MAMP, or XAMMP or one of the similar packages, but you didn't say.
Viewing, adding and editing database data in Drupal requires reading and understanding the Drupal database API https://www.drupal.org/developing/api/database

Create custom column in post table in wordpress

I want to add two custom field to table wp_posts, and that I need for my plugin.
now to enable these fields I have changed core file of wordpress
wordpress/wp-admin/post.php
$data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' ) );
here I have added two fields which I want.
Now I want these things as installable( I have manually added two fields here).
So how to do that within plugin.
I have read one post
http://wp.tutsplus.com/tutorials/creative-coding/add-a-custom-column-in-posts-and-custom-post-types-admin-screen/
here hooks are used in theme function.php,but i want to do in plugin itself.
I am using wordpress 3.6.
still any confusion please comment I will update.
As pointed in the question comments, you should never edit wp core files(reason: they get overwritten at updates), and you should never modify wp tables (can cause crashes at updates).
You are developing a plugin, then you have a few options for the database setup:
1) you can use existing database tables
* you might use the postmeta table
2) if for any reason you can't use post meta, create your own table
* add the 2 columns that you need and a column as post id, this way things will run smoothly
PS: you can use in your plugin all wordpress functions, just search them in the codex and see how you need to use them.
also check this info about creating database tables with plugins

migrating node references

I am working on a project to migrate a website from asp.net to drupal architecture. But the site content is very hierarchal and has a lot of references between entities.
for example: each content belongs to a category, and each category belongs to another category section. Now there may be another level of hierarchy even.
I am planning to make use of migrate module for migrating the database content and linking the migrated nodes via a node reference field.
But i am getting stuck with migrate module as i can't find a way to migrate the node reference field anywhere...
can anyone help me out with this...
Actually, it doesnt seem to be that hard .. in 2012. Yes, you have to keep track of source IDs versus import IDs, but the migrate module does this for you, in a neat little table. You can join that table in your source query, and update the node reference field with the nid of the .. referenced node. Ofcourse, the referenced nodes should have already been imported. If they werent, you can run an run an 'update' later and referenced nids get entered based on the latter imports too. In practice:
$query = Database::getConnection(
'default', 'mysourcedb'
)->select(
'mysourcetable','source'
)->fields('source', array(
'id',
'title',
'whatever'
'rel_rec_id'
)
);
$query->leftJoin('migrate_map_relimport','relmap','relmap.sourceid1=source.rel_rec_id');
$query->addField('relmap','destid1','rel_node_id');
The code above assumes you have a 'mysourcedb' with a 'mysourcetable' in it that refers to a 'rel_rec_id', and theres another import called RelImport that imports the rel table that rel_rec_id is refering to; it should have already run (or will run before you run an additional update). Do a migrate-status once you have the RelImport class to make sure the table exists.
To be able to make joins to the 'migrate_map_relimport' table, make sure map tables are written to the source database, not the drupal database. This is not always necessary, but here it is:
$this->map = new MigrateSQLMap(
$this->machineName,
array(
'id' => array(
'type' => 'int',
'unsigned' => true,
'not null' => true,
'alias' => 'source'
)
),
MigrateDestinationNode::getKeySchema(),
'mysourcedb' // connection to use to write map tables
);
and finally, assign the retrieved rel_node_id to your node reference:
$this->addFieldMapping( 'field_rel_node', 'rel_node_id' );
Yay, it is rocket science .. YMMV
As far as I know, you will not be able to do this entirely within the migrate module. You'll have to run a few queries directly in MySQL.
Essentially, you'll have to create an extra field in each content type to house their legacy ID's and an additional field for each legacy reference (in addition to the actual nodereference field). Load all the data into the content types (leave the nodereference field empty). Then once all of the entities are loaded in, you run mysql queries to populate the nodereference fields based on the legacy IDs and legacy reference fields. Once that's done you can safely delete these legacy fields.
Not the most elegant solution, but I've used it many times.
Caveats:
This is for Drupal 6; Drupal 7's fields implementation is totally different AFAIK.
For very large migrations, you might want to do your legacy field deletions through MySQL.
You might also take a look at the code for the Content Migrate module (more information at https://drupal.org/node/1144136). It's for migrating D6 Content Construction Kit (CCK) content to D7 Fields and it's been integrated with the References module.
It won't do what you need out of the box, as you're coming from an ASP.net site instead of a D6 site, but it may provide some clues.

Combining databases in Drupal

So here's the scenario:
I am building a series of event websites that need to be separate Drupal-6 installations on the same server. Each uses the same architecture but different URLs and themes.
What I'd like the sites to be able to share is content in 2 content types, teachers and sponsors. So that there would be one database with all the teachers and sponsors that each individual event site could then pull from by means of nodequeues.
So that new teacher nodes and sponsor nodes can be created and edited from within any of the Drupal installations.
It would also be convenient to share a user table as well, but not absolutely necessary.
Any ideas?
Does this help you?
The comments in settings.txt explain
how to use $db_prefix to share tables:
* To provide prefixes for specific tables, set $db_prefix as an array.
* The array's keys are the table names and the values are the prefixes.
* The 'default' element holds the prefix for any tables not specified
* elsewhere in the array. Example:
*
* $db_prefix = array(
* 'default' => 'main_',
* 'users' => 'shared_',
* 'sessions' => 'shared_',
* 'role' => 'shared_',
* 'authmap' => 'shared_',
* );
Another way, although I don't know if that would work, is to create one database per Drupal installation and create in each database a VIEW eg. install1_users, install2_users that refers to one shared table shared_users in a shared database. A carefully constructed view should be updatable just like a normal table.
Sounds like a job for the Domain Access project, a suite of modules that provide tools for running a group of affiliated sites from one Drupal installation and a single shared database. The module allows you to share users, content, and configurations across a number of sites. By default, these sites share all tables in your Drupal installation but the Domain Prefix module allows for selective, dynamic table prefixing for advanced users.
IMHO this is much better than rolling a custom solution which poses considerable complexity and risk of not being able to upgrade your site. See Share tables across instances (not recommended).
There are a couple of ways of doing this.
If it's okay to share a single database, you can use prefixing as follows:
$db_prefix = array(
'default' => 'main_',
'users' => 'shared_',
'sessions' => 'shared_',
'role' => 'shared_',
'authmap' => 'shared_',
);
However, keep in mind that there is a hard limit to the number of tables that a MySQL database can hold. According to this thread, it's 1792. If you suspect that you will reach this limit, you can use this hack/bug.
$db_prefix = array(
'default' => '',
'users' => 'maindb.',
'sessions' => 'maindb.',
'role' => 'maindb.',
'authmap' => 'maindb.',
);
where maindb is another shared database that contains the data that you need. This is not best practice, but it works in Drupal 6 (haven't tested in D7).

Resources