Viewing, adding and editing database content - drupal

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

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:

Saving user meta as single values or an array

I'm working on a plugin which is going to save about 10 custom user meta for certain users bound to the plugin. Among these metas we find: Address, zip, occupation, etc...
These metas will only be used by the plugin, and mostly (if not always) all of them will be fetched from the DB together to be shown in a table view in the admin.
So, I'm thinking about the best way to save these values.
I could do this:
add_user_meta( $user_id, 'address', 'kings street 45');
add_user_meta( $user_id, 'zip', '12345');
add_user_meta( $user_id, 'occupation', 'nurse');
... some more meta
Or would it be better to do this:
add_user_meta( $user_id, 'plugin_name_user_meta', array(
'address' => 'kings street 45'
'zip' => '12345'
'occupation' => 'nurse')
... some more meta
);
In WordPress I prefer to work with arrays because in helps keeping my data organized, so I would go the second way. Nevertheless, if you go the first way, prefix all the metas with a unique ID related to your plugin.
I disagree with the first answer and I would use your first suggestion.
Why? Because if you use add_user_meta for each field you have a seperate field in the database for each value. That means:
1) You can do meta and Wildcard Queries e.g. "Select all user with a ZIP starting with 11". This is impossible if you save an array especially as the array will be saved in serialized format.
Keep this possibility open! Some day you may want to do complicated queries on this data even if it is not the case currently.
Have a look at the WP Meta Query class and even better the WP User Query class:
https://codex.wordpress.org/Class_Reference/WP_Meta_Query
https://codex.wordpress.org/Class_Reference/WP_User_Query#Custom_Field_Parameters
2) You do not have a disadvantage in extensibility: As these fields are already saved in a meta table and not within fixed columns you can add and remove values dynamically.
However #Juan is right with the hint on prefixes: You definitly should prefix your meta_values in order to avoid collisions.

how to store custom plugin data to database without using custom table in wordpress

I am developing a wordpress plugin , where I need to store some custom data to database .
Custom data what I want to store like "class title" , "numeric name of class (it will be an integer value) " . Site admin could add those data every time he wants.
To get those data from site admin I have created a form. But I am having problem while storing those data to database . I dont want to use custom table . So I used options api for store those data . I used this function to store data
add_option('class_title', $class_title);
add_option('class_numeric', $class_numeric);
But using this method , user could add data to database only once . But I need to store data more than one time with same option name (in this case ,'class_title' and 'class_numeric').
How could I able to store those custom data to database with same option name more than one time using options api or any other way without custom table. If there are not any other way , then I will use custom table .
You can add a post type, but you could also serialize your option, ie. storing it as an array of array
myoptions = array (
0 => array ('class_title' =>$class_title, 'class_numeric'=>$class_numeric ) ,
1 => array ('class_title' =>$class_title, 'class_numeric'=>$class_numeric ) );
Depending of what you want to achieve, both solutions have their advantages. The second one would be better from a performance point of view.
I think an easy way would be to add a post type.
WordPress 3.0 gives you the capability to add your own custom post types and to use them in different ways.

How to use Catalyst to search, select and display entries from my database

I have to use Catalyst in order to create a database and access it through a browser.
I have created a very simple database using DBIx-class and sqlite, just one table and filled it with some records.
I have managed to display the whole table and its rows using Template Toolkit view module and the code below into my controller.
$c->stash(ptm => [$c->model('DB::ptm')->all]);
Now I have created a simple search box in order to search the database and display any entries that match with the keyword, but I don't know how to pass the keyword to my controller nor how to implement the subroutine in order to achieve this.
I have searched for more than three days without finding any solution.
There are two completely different problems here.
Accepting arguments in Catalyst
Performing a search in DBIC
So, starting with the first one. Reading a query string.
$c->request->query_parameters->{field}
Then performing a search. Just call search instead of all and pass a hashref of your columns and values.
$c->model('DB::ptm')->search( { 'name' => $tag } );

Drupal: help with content type creating & linking nodes

I have a situation where someone can create a job content type. I've added a CCK field that is related to the 'organisation' content type. So when someone creates a new job posting they can choose which organisation the job is for in that field (auto completed). The problem is I can create a new job and select any organisation, even if I didn't create that organisation myself.
Is there a way I can restrict what someone types in that field to 1. an organisation name that exists, and 2. an organisation that belong to that user?
I'm using drupal 6.
Any help most appreciated!
Jonesy
You can use a php rule for the allowed values array of your node reference field, which I think in your case would need to run a quick query for all the nodes made by the current user.
I have not tested this code, but it should be reasonably close to what you're after if I have understood the question!
global $user; //make sure we have access to the user
//find all the job organisation nodes made by this user
//(replace organisation with the actual name of your content type)
$query = db_query("select nid from {node} where type = 'organisation' and uid = %d", $user->uid);
//put the results in the values array
$values = array()
while($result = db_fetch_result($query)){
$values[] = $result;
}
I'm not in a place where I can check this easily, but you could also try using a select on the edit page, and display the choices with a view. Then, create a view over the content type and check that the node user is the logged in user.
You could use a Nodereference field.
It's Autocomplete, and on the bottom of the settings of the field, you can select a View to filter the Nodes that can be referenced ( it's called "Advanced - Nodes that can be referenced (View) ")
Just make a View limiting the nodes to nodes that the current logged in user created, and use that on the Nodereference settings page.
Using that option, drops the option 'Content types that can be referenced' which is located above the Advanced settings.
So make sure to add a filter on node type.
I assume you already use Nodereference, and you might have looked past that option

Resources