When does the $op parameter of hook_search() get defined as 'search'? - drupal

Edit
The basic question here is "when does the $op parameter get defined as 'search'"?
I am trying to create a custom search in an implementation of hook_search(). I have been looking through the Drupal documentation for the method here: http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_search/6
I know the method is running because I can slip a die('killed inside of implementation of hook_search()') into the top of the function and see the output.
In the following code, the script is never killed so that I can see the output search caught inside of my_search(). This leads me to believe that the 'search' case of the switch statement is never firing. Does anybody know where I might go from here?
/**
* Implementation of hook_search()
*/
function my_search($op = 'search', $keys = NULL) {
switch($op)
{
case 'search':
die('search caught inside of my_search()');
break;
}
}

First things first.
Assuming your module is called 'my', try to go to URL /search/my/whatever - probably you will see access forbidden page (assuming you do not have anything more in your code besides what you have pasted in your question).
That's because you do not return anything when search module calls your hook with $op = 'name' (see _search_menu() in search.module). You need to return "a translated name defining the type of items that are searched for with this module ('content', 'users', ...)" - see http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_search/6 And access forbidden gone.
Once this is done, search will call your hook again (actually, there are quite a few calls, you can for example drupal_set_message($op) in your hook to see them all), and one of those calls will be with $op = "search" as well (coming from search_data() in search.module).

Related

symfony2 routing requirements combining 2 parameters

So I got this in my routing.yml:
requirements:
var1: \d+
var2: \d+
Both are checked on their own and valid.
I need to check the combination of the 2, since the combination is not always valid.
For this case I need to check the relation between 2 objects in the database, the first should be the parent of the second.
I can do this in the controller, but I don't really like that implementation. Also, I need this same check for more than 1 route.
How would I add another requirement that checks the combination? Can I define a method in the controller class that would be called?
Or would the best solution be something like:
public function indexAction($var1, $var2)
{
$result = $this->checkRelation($var1, $var2);
if ($result) {
// return errorpage
return $result;
}
// ...
}
So as I understand your question, you want the following:
/parent/child/ --> returns 200
/not_parent/not_child --> returns 404
The Symfony2 Routing component doesn't do this natively, but you could extend it.
http://symfony.com/doc/master/cmf/cookbook/using-a-custom-route-repository.html
The final solution I went with was the following:
add a method checkRelation that requires all parameters
run a query inside that method to check if everything is ok.
return false when there is a problem, return true when values are ok. (alternatively you can return an object or something)
in the action I check if the value is false, if so I return a generic "not found" page for the specific controller.
In all this is very similar to what I posted in my initial question.
When using the same checkRelation in multiple controllers it might be a good idea to move it (partially) to a repository-class or something similar to prevent duplication of code/logic.

onAfterWrite method called twice with DataObjectManager

I am using dataobjectmanager with a many_many relationship (I can't use manymanydataobjectmanager for this) between owner and car. Whenever a new car is created I iterate through all instances of owner and add it's id to a linked table along with the new car ID.
My problem is that the code for doing this is within the onafterwrite method and is called twice. I'm not sure why. I've also noticed that for my three owners it is creating rows in the linked table oddly. The first two IDs will be in order then it will stick one. So it'll be rows 1, 2 and 4 with no 3.
This is my onAfterWrite method
public function onAfterWrite() {
if(Permission::check('ADMIN')){
$Pages = DataObject::get('Owner');
foreach($Pages as $owner) {
DB::query("INSERT INTO Owner_Cars (OwnerID, CarID) VALUES ('". $owner->ID . "', '" . $this->ID . "')");
}
}
else {
echo "Failure";
return false;
}
return parent::onAfterWrite();
}
I'd appreciate any advice you could give me.
Thanks
The onAfterWrite() method is probably called twice because write() is called twice. The most common reason that this happens is that:
A write() happens to generate the ID
Then another write() happens as part of saving related records that rely on that ID.
In general, I don't think you can rely on onAfterWrite() being called once: write() is supposed to be designed so that it can be called any old number of times and will only actually affect the database if there are changes to be made.
You would need need to make your code call the necessary DELETE, INSERT, and/or UPDATE statements to be compatible with this. You might, for example:
Select all the Owner_Cars records where OwnerID = $owner->ID
Delete any not in the $Pages list
Insert any from the $Page list that aren't already in Owner_Cars
One other suggestion I would make, if you can, is to try out SilverStripe 3. SilverStripe 3's GridField handles this kind of stuff more robustly out of the box and you might find it easier to build your app on that.

In Drupal 7, why is autocomplete not attaching to this list of form elements?

I'd like to attach autocomplete to a particular list of fields in Drupal 7. The fields have FIELD_CARDINALITY_UNLIMITED, so there could be anywhere from 1 to whatever. I'm using the following code:
function mymodule_form_alter(&$form, &$form_state, $form_id) {
if (array_key_exists('mymodule', $form)) {
$indices = array_filter(
array_keys($form['mymodule']['und']),
function($item) {
return is_numeric($item);
}
);
foreach($indices as $index) {
$form['mymodule']['und'][$index]['value']['#autocomplete_path'] = 'api/node/title';
}
}
}
...however, my autocomplete behavior is not being attached. I've used the exact same code in a similar situation - the only difference is that I was adding the autocomplete to a field that had a cardinality of 1 rather than unlimited. That doesn't seem like it should change anything. I've verified that the autocomplete is attaching by doing a debug($form['mymodule']) after the assignment statement, and it is definitely there. I have also debugged the exact array path I am trying to get in each iteration of the foreach loop, and it is definitely the correct form value.
EDIT: Is it possible that the issue is with more than one module altering this form using hook_form_alter()? I'm performing the exact same operation as above (but on a single field) in a different module, on the same form.
EDIT2: I've noticed that if I put a debug statement inside the foreach loop, I see the autocomplete value is set on the proper value each iteration. If I place the debug statement outside the foreach loop, the autocomplete path is no longer set. Somehow, either during the course of iteration, or after iteration, it looks like my changes are being destroyed? I tested this by assuming $index to be 0, and writing a hard-coded statement to attach autocomplete - this allowed auto complete to work correctly. To be clear, I am seeing something like the following:
function mymodule_form_alter(&$form, &$form_state, $form_id) {
if (array_key_exists('mymodule', $form)) {
$indices = array_filter(
array_keys($form['mymodule']['und']),
function($item) {
return is_numeric($item);
}
);
foreach($indices as $index) {
$form['mymodule']['und'][$index]['value']['#autocomplete_path'] = 'api/node/title';
// Debug statements here show that the value '#autocomplete_path' is set properly
debug($form)['mymodule']['und'][$index]['value']);
}
// Now, the '#autocomplete_path' key does not exist
debug($form)['mymodule']['und'][0]['value']);
// This will make autocomplete attach correctly
$form['mymodule']['und'][0]['value']['#autocomplete_path'] = 'api/node/title';
}
}
You've spelt it #autcomplete_path...it should be #autocomplete_path :)
If you're defining the field (and widget) yourself then you should just add the autocomplete in your module's implementation of hook_field_widget_form() rather than altering the form.
If you're not defining the widget yourself, take a look at hook_field_widget_form_alter() and hook_field_widget_WIDGET_TYPE_form_alter() which will let you alter the widget form for a specific field.
Try this:
1) change ['mymodule']['und'][$index]['value'] in your code to the id of your text form input example
$form['search_form_block']
['#autocomplete_path']='yourcall_back_function_which_returns_data';
I think the mistake is your are trying to work to replace the value of the the field but you have to change the value of the format widget. In this case the input field.
2) Also make sure 'api/node/title' call back works using x debug.
Let me know if it worked.
Cheers,
vishal
I resolved the problem by manually enumerating my indices rather than programmatically doing so, e.g. $form['mymodule']['und'][0]... - this appears to be a PHP issue related to scoping of variables in foreach rather than a Drupal problem.

Modifying the user object with hook_user_load()

In Drupal 6 you could use code similar to the following one:
function example_user($op, &$edit, &$account, $category = NULL) {
switch($op) {
case 'load':
$account->fb_id ='xyz'
break;
}
}
In Drupal 7, the documentation for hook_user_load() states the following:
Due to the static cache in user_load_multiple() you should not use this hook to modify the user properties returned by the {users} table itself since this may result in unreliable results when loading from cache.
Why do I get users and not just a user?
Is it ok to add properties to this?
http://api.drupal.org/api/drupal/modules--user--user.api.php/function/hook_user_load/7
You get an array of user objects because the hook is called from user_load_multiple(), which generally calls DrupalDefaultEntityController::load(), which then calls DrupalDefaultEntityController::attachLoad().
It is fine to add custom properties, but not to override the default properties that are loaded from the {users} table; as reported from the documentation, in that case you could get some problem when loading the user object from the cache, which is what the entity API normally does.

hook__form_alter resetting &$form

I am doing some access to content using hook_form_alter as there are problems using hook_access with content types defined outside of your module. If a user does not have access I am setting a message at the top of the page and I don't want to output the form. I have the following code.
function mymodule_form_alter(&$form, $form_state, $form_id) {
switch ($form_id) {
case 'cmyformm':
dsm($form);
$from = null;
dsm($form);
drupal_set_message('You do not have access to this page');
break;
}
}
The dsm however is returning the same information for $form even if I set it to null. How do I not display the form but a message?
I don't quite understand the question, but for starters you are setting $fROm to null and not $fORm. Setting for to null or just doing unset($form); should do the trick.
Access control shouldn't be done at the form level. Access control should be implemented with hook_access or in the router's access arguments. If you must do this at the form level, use user_access() along with the defined roles that you have.
In addition to the typo as pointed out by #zeroFIG, you are really doing this access check in the wrong way. I have used the node_example module with sucess on all node types - none were defined in the same module as the hook_access. Have a look here: http://api.drupal.org/api/examples/node_example--node_example.module/6

Resources