I have a Drupal 7 site that has a customized theme installed on it and we have also added some new tables and extended some others.
Right now I have set up Ubercart for selling our products based on the taxonomy. When the purchase is complete I need to update a custom table in MySQL so I made a proc to do that.
In MySQL the created a proc that will do the updating of the tables that I need, all I need to pass into the proc is the uid (same as from the users table) and an id of the taxonomy that was selected during purchase.
I have created the following code to make the call but I am not sure what the best way to pass in the uid and tid to the proc? Should I be using rules within Drupal?
<?php
$mysqli = new mysqli("mysite.com", "user", "password", "db1");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
if (!$mysqli->query("CALL UpdateUserDestList(uID, tID")) {
echo "CALL failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
?>
You can fire your code after a purchase using Ubercart's hook_uc_checkout_complete(). You will want to define that in a custom module, not from within the theme since this is business logic not display information. From within the hook you will have access to both the order and the user account that placed the order.
When working with Drupal, or any other framework really, you should leverage the built-in tools when you can to benefit from the structures they provide.
// Get the Drupal database connection and change the statement class to PDOStatement.
// Save the current class for cleanup later.
$conn = Database::getConnection();
$saved_class = $conn->getAttribute(PDO::ATTR_STATEMENT_CLASS);
$conn->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement'));
// Prepare the statement and bind params
$statement = $conn->prepare("Call GetNodeList(?,?)");
$op_status = $statement->bindParam(1, $node_type, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 25);
$op_status = $statement->bindParam(2, $publish_state, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT);
// Execute the statement and reset the connection's statement class to the original.
$exec_result = $statement->execute();
$conn->setAttribute(PDO::ATTR_STATEMENT_CLASS, $saved_class);
// Get your data
while ($row = $statement->fetchColumn(0)) {
// ...
}
Code taken from: https://drupal.stackexchange.com/questions/32708/how-to-execute-stored-procedures-in-drupal which in turn cites: http://public-action.org/content/stored-procedures-and-drupal-7
Related
I'm looking for a way to get a list of all available table objects. These are all the classes that are (by default) located under App/Modal/Table and that are handled by TableRegistry. How to get a list of all those objects?
I know it's possible to fetch all tables of the db:
$tables = ConnectionManager::get('default')->schemaCollection()->listTables();
And then using TableRegistry::get() to get the table object.
But this is not possible for my solution, because there are two cases where this does not work:
custom table names that are different to the table object name
plugin table objects
Any ideas?
Edit: Why? I need all table objects that use a behavior X. In my case a custom SearchableBehavior, which updates a searchindex table on each afterSave event for the saved entity. To update the searchindex for all entities of all tables, I need to know which tables are using the SearchableBehavior and call their update method manually.
$tables = glob(APP."Model".DS."Table".DS."*Table.php");
$tablesNames = [];
foreach ($tables as $name){
$item = explode('Table.php', basename($name));
$tablesNames[] = $item[0];
}
pr(tablesNames);
Write an event listener that listens on Model.initialize and then do a check on the subject, which is the table object if the table has your behavior. Then do something with that list.
If this doesn't work for you - you give zero background info - iterate over the apps Model/Table folder and plugin folder and the vendor folders and search for Model folders and check for *Table.php files. Then try to instantiate the table objects based on the path / namespace and filename and check the models. But this is not very fast, you should cache the resulting list.
I recently had a similar use case, where I needed to access all Table Objects, to initialize the data in the database once, in a console command.
I did it by first building an array of all the paths where the Table Object Classes could reside, then iterating over all files and using the ones ending in "Table.php". Note that this approach might need to be modified slightly depending on your use case.
<?php
use Cake\Core\Plugin;
use Cake\ORM\TableRegistry;
use Cake\Filesystem\Folder;
// Building an array of all possible paths. Firstly the src directory:
$tableClassPaths = [
APP . 'Model' . DS . 'Table' . DS,
];
// Secondly, all loaded plugins:
foreach(Plugin::loaded() as $plugin) {
$dir = Plugin::classPath($plugin) . 'Model' . DS . 'Table' . DS;
if(is_dir($dir)) {
$tableClassPaths[$plugin] = $dir;
}
}
// Iterating over each file in each folder.
$tableObjects = [];
foreach($tableClassPaths as $plugin => $dir) {
foreach(new \FilesystemIterator($dir) as $file) {
// All Files ending in Table.php might be relevant
if($file instanceof \SplFileInfo && $file->isFile()
&& mb_substr($file->getFilename(), -9) === 'Table.php'
) {
$className = mb_substr($file->getFilename(), 0, -9);
if(is_string($plugin)) {
$className = $plugin . '.' . $className;
}
$tableObject = TableRegistry::getTableLocator()->get($className);
// Here you can use / filter the Tables, for example by checking for the presence of a behavior "Indexable":
if($tableObject->hasBehavior('Indexable')) {
$tableObjects[] = $tableObject;
}
}
}
}
?>
Keep in mind, that this is only really suitable for very narrow circumstances, since this completely sidesteps the regular MVC patterns of CakePHP.
I have a Model from which I want to select all rows for which 'caller' or 'callee' is a given value for presentation in a Grid.
I have tried lots of different avenues of accomplishing this and cannot get anywhere with it.
I have a working filter on the Grid which narrows down the results by date (starting and ending dates), by status ("ANSWERED","NO_ANSWER"), I can also add conditions for 'caller' and 'callee', but how do I get it to show all rows where either 'caller' or 'callee' is a match to the current $UserID? Basically showing all calls (rows) a user was involved in?
The MySQL query itself is a simple OR construction, but how do I 'feed' it into the Model or the Grid so that it plays nicely with the other filters on the page?
You can use orExpr() method of DSQL to generate SQL for your needs.
For example,
$m = $this->model->debug(); // enable debug mode
$user_id = $this->api->auth->model->id;// currently logged in user ID
$q = $m->_dsql(); // get models DSQL
$or = $q->orExpr(); // initialize OR DSQL object
$or->where('caller', $user_id) // where statements will be joined with OR
->where('callee', $user_id);
// use one of these below. see which one works better for you
$q->where($or); // add condition with OR statements
$q->having($or); // add condition with OR statements
Of course you can write all of this shorter:
$m = $this->model->debug(); // enable debug mode
$user_id = $this->api->auth->model->id;// currently logged in user ID
$q = $m->_dsql(); // get models DSQL
$q->where($q->orExpr()
->where('caller', $user_id)
->where('callee', $user_id)
);
I have three entities : Event, Photo and User.
Three main relations :
An Event has 0 or more photos (blue relation, OneToMany)
An Event has been created by one photo, which I call the firstPhoto (red relation,
OneToOne)
A user can create 0 or more photos (violet relation,
OneToMany)
What I want is to map the relation between an Event and the User who created it, without adding or changing my database. It means the user that created the firstPhoto of the Event.
I'm not looking for a SQL query which I succed to do but really a mapping in my User.php Entity.
$user->getEvents() would give the events the user created.
I can't success to do so... any idea ? Am I obliged to add or change something in my database ?
I see 2 ways of doing that:
1) make a named native query http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html#named-native-query
2) write something like
public function getEvents()
{
$res = array();
$photos = $this->getPhotos();
foreach($photos as $photo) {
$res[] = $photo->getEvent();
}
return $res;
}
I have two profile2 profiles defined - main and customer_profile. Also, I have a node type called Customer.
When creating a new Customer node, I would like to load the custom_profile form. The idea is to create a node and a profile simultaneously.
I know it's definately a hook_form_alter solution but can someone tell me how to programmatically load a profile while creating or editing a Customer node.
You can load profile type and data by using these function
$types = profile2_get_types();
profile2_load_by_user($account, $type_name = NULL)
For Example :
$types = profile2_get_types();
if (!empty($types)) {
foreach ($types as $type) {
$profile = profile2_load_by_user($uid, $type->type);
}
}
Even if you are able to load the customer_profile form, you will need to handle the values separately as they are two different nodes.
I would suggest capturing those fields in the customer node form, and then create a customer_profile programmatically from the values.
If you want to get the profile2 form itself then you can use something like
module_load_include('inc', 'profile2_page', 'profile2_page');
$profile2 = profile2_by_uid_load($uid, 'seeker_profile');
$entity_form = entity_ui_get_form('profile2', $profile2, 'edit');
and then add that to the form you want to place it in.
You can load full profile data using profile2_load_by_user();
params like:-
profile2_load_by_user($account,$type_name)
$account: The user account to load profiles for, or its uid.
$type_name: To load a single profile, pass the type name of the profile to load
So code like bellow
$account->uid = $existingUser->uid;
$type_name = 'user_about';
$profile = profile2_load_by_user($account, $type_name);
//$profile variable have full data of profile fields
//changing data profile2 fields
if(isset($_POST['field_user_first_name'])&& !empty($_POST['field_user_first_name'])){
$profile->field_user_first_name['und'][0]['value'] = $_POST['field_user_first_name'];
}
profile2_save($profile);
Well When creating a new Profile , Profile2 fields are not visible until a manual save is done.
To Automatically create the profile2 object , We use rules Module
Step
1) Go to Drupal admin/config/workflow/rules
2) create new rule
3) Give a name and Select in react/event "After saving a new user account"
4) Action,>> Add Action >> Execute custom PHP code
5) insert php code
$profile = profile_create(array('type' => 'profile2 type machine name', 'uid' => $account->uid));
profile2_save($profile);
6)Save >> Save changes.
This will create profile2 field when a new user is Created.
I had a similar need for creating a custom tab at the user page and loading the user profile2 form in it.
Here is a snap code of how I managed to accomplish just that:
MYMODULE.module https://gist.github.com/4223234
MYMODULE_profile2_MYPROFILE2TYPE.inc https://gist.github.com/4223201
Hope it helps.
I am new to code igniter data mapper. I have a table called user, and I am trying to retrieve data from the database table and show them to the user.
Here is what I have in the model:
$u=new User();
$results=$u->get_by_user_id($id);
//$results here will be set to huge bunch of none sense data( which also includes the row that I am looking for as well)
if ($u->exists())
{
foreach ($results->all as $row){
$data['user']['first_name']=($row->user_first); //this where I am stuck ..
$data['user']['last_name']=($row->user_last);//this is also where I am stuck..
}
I don't know how to treat results to get a required fields I am looking for and store them in the $data I am passing to the user to view.
Thanks!
When you call get_by_x() on the model, the fields will be populated with data and you can access them like this:
$u = new User();
$u->get_by_user_id($id);
if($u->exists())
{
// you can access the table columns as object fields
$data['user']['first'] = $u->first;
$data['user']['last'] = $u->last;
}
else
{
$data['error'] = 'No such user!';
}
Have a look at the documentation which is really helpful: see Get and Get By.
Also, DataMapper expects all tables to have an id column: see Table Naming Rules. If your column is named id you should then call $u->get_by_id($id) instead of $u->get_by_user_id($id).