Drupal 7 hook_node_access not allowing "deny"? - drupal-7

I created a simple module:
function hook_node_access($node, $op, $account)
{
return NODE_ACCESS_DENY;
}
It does block the access to the node, but I get this error when visiting that page:
Notice: Trying to get property of non-object in node_node_access() (line 3089 of \www\modules\node\node.module).
This line reads:
3088. function node_node_access($node, $op, $account) {
3089. $type = is_string($node) ? $node : $node->type;
So basically, when I do this, $node is NOT a string, but also doesn't have a "type" value. I can only imagine that $node is a blank object when it hits this part of the code. But why?
UPDATE
I did a var_dump of the "node" object and I believe this is the contents:
int(436)
So, somehow the node id is getting pushed into this function, but not the node, AND the is_string function is not picking up that it's a string (because it isn't, it's an INT).
Any ideas?
UPDATE 2:
What makes all of these really bad for me, is that even though I'm logged into Drupal as a user that does not have access to these nodes, they still see them if they go to /node and scroll through the pages.
Am I missing something, because surely hook_node_access should block the nodes from being seen at /node ?

When implementing Drupal hooks, you should always replace 'hook' with your custom module name. For example:
function mymodule_node_access($node, $op, $account)
{
return NODE_ACCESS_DENY;
}
Also, you will need to clear out the Drupal cache each time you implement a new hook by going to admin/config/development/performance

Related

Calling push() on array, TypeError: Attempted to assign to readonly property

Working in React Native. I'm trying to declare an array and then push things to said array, but I'm getting the error TypeError: Attempted to assign to readonly property
CONTEXT:
The app prints via a thermal printer.
The print method receives an array of commands
Example:
print([{appendText: "blah"}, {
appendCutPaper: StarPRNT.CutPaperAction.PartialCutWithFeed,
}]
The print method is asynchronous and if you attempt to call the method again before the last call has finished, it errors.
Because of #2, we created a queue system that accepts a job (array of commands) and then works through the jobs synchronously.
In a React component, I'm attempting to create a job by declaring an empty array named printJob
and then pushing various commands to it. In this case, we take a snapshot of a View and then push the commands returned by the printImage method to the printJob array.
onClick={() => {
const printJob = []
viewShot.current
.capture()
.then((uri) => {
printJob.push(...printImage(uri))
})
.catch((err) => alert(err))
newPrintJob(printJob)
}
printImage returns the array of commands to print an image and cut the paper:
const CUT_PAPER = {
appendCutPaper: StarPRNT.CutPaperAction.PartialCutWithFeed,
}
export function printImage(uri) {
return [{ appendBitmap: uri }, CUT_PAPER]
}
So the goal is to generate the array of commands and pass that to the queue as a job. Now, I could just do newPrintJob(printImage(uri)) in the above case, which works completely fine. However, there is a particular setting the user can configure where it will need to print multiple images, one per ticket (in other words, multiple printImages). I want to consider all of that one job, hence the need to create the printJob array.
THE PROBLEM:
I'm getting an error TypeError: Attempted to assign to readonly property which seems to be triggered by printJob.push(...printImage(uri)). If I comment that line out, the error doesn't get thrown.
I don't understand why this would happen because you can call push on an array, even if it's declared as a constant. I also tried declaring it with var and let and still received the same error.
I hope I've provided enough context here. LMK if I need to add more.
Additional info:
"react": "16.13.1"
"react-native": "~0.63.3"
Turns out the issue was not pushing to the array. The issue was was trying to add the job to the queue:
newPrintJob(printJob)
...outside of the async's callback. Solution was to move the newPrintJob line into the .then block.

Why is my object not changing when I reassign properties in a forEach loop?

I am fetching an array of objects from an RX/JS call from an http backend. It returns an object which I am then trying to work with. I am making changes to this object using a for loop (in this example I am trying the .forEach because I have tried a number of different things and none of them seem to work.
When I run the code, I get a very weird problem. If I return the values of the properties, I get the new values (i.e. correctionQueued returns as true, etc.) but in the very next line, when I return the object, those same values are the same as the original (correctionQueued === false, etc.) HOWEVER, correctionStatus (which does not exist on the original object from http) sets just fine.
I don't understand how
array[index].correctionQueued can return true, but
array[index] returns an object with correctionQueued as false.
After the loop, the original array (checklistCopy) is identical to the object before the forEach loop, except the new property (correctionStatus) is now set, but all properties that I changed that were part of the original object remain as they were.
I have tried using a for of, for in, and .forEach. I have used the index to alter the original array, always the same result. Preexisting properties do not change, new properties are added. I have even tried working on a copy of the object in case there is something special about the object returned from rxjs, but to no avail.
checklistCopy.forEach((checklistItem, index, array) => {
if (checklistItem.crCode.isirName === correctionSetItem) {
array[index].correctionQueued = true;
array[index].correctionValue = mostRecentCorrection.correctionValue;
array[index].correctionStatus = mostRecentCorrection.status;
console.log(array[index].correctionQueued, array[index].correctionValue, array[index].correctionStatus);
console.log(array[index]);
}
}
);
I don't get an error, but I get..
Original object is:
correctionQueued: false;
correctionValue: JAAMES;
--
console.log(array[index].correctionQueued, array[index].correctionValue, array[index].correctionStatus);
true JAMES SENT
but when I print the whole object:
console.log(array[index]);
correctionQueued: false;
correctionValue: JAAMES;
correctionStatus: "SENT'; <-- This is set correctly but does not exist on original object.
console.log(array[index]) (at least in Chrome) just adds the object reference to the console. The values do not resolve until you expand it, so your console log statement is not actually capturing the values at that moment in time.
Change your console statement to: console.log(JSON.stringify(array[index])) and you should discover that the values are correct at the time the log statement runs.
The behavior you are seeing suggests that something is coming along later and changing the object properties back to the original value. Unless you show a more complete example, we can't help you find the culprit. But hopefully this answers the question about why your logs show what they show.
Your output doesn't make sense to me either but cleaning up your code may help you. Try this:
checklistCopy.forEach(checklistItem => {
checklistItem.correctionQueued = checklistItem.crCode.isirName === correctionSetItem;
if (checklistItem.correctionQueued) {
checklistItem.correctionValue = mostRecentCorrection.correctionValue;
checklistItem.correctionStatus = mostRecentCorrection.status;
console.log('checklistItem', checklistItem)
}
}
);

drupal 7 file field formatter on custom node for javascript (to set up jQuizMe)

I have set up a module with custom node type (I called jquizme, after the javascript jQuizMe that I really like using). I set up two fields for the javascript files I need to supply to make it work (after the general jQuizMe-2.2.js file you need to add another two javascript files - one for settings and one for the quiz content).
Drupal saves the files as myjavascriptfile.js.txt - I tested them and they still work to make the jQuizMe interface - ok. the problem is, I want to add these files on the node page... the files will be different for each node. how can I access the files for the drupal_add_js() function so they will load the files for the node in question?
I tried setting up custom field formatters, but I don't know how to access the uri for the files of a given node automatically to put in the drupal_add_js() function (I can add a static file and it loads fine ... I did this with hook_node_view ( jquizme_node_view ).
So I just need a way to access the info for the files... how are they linked to each node? I can't find the connection.
As you probably noticed, I am a module writing newbie, and I probably won't understand much related to object oriented programming sorry, haven;t progressed to that level yet), but I am open to any answer. I am sure I left out important info, but this it already getting too long.
I also set up a special page earlier on to just see if I could get jQuizMe to work in Drupal so that is still in the code.
I have tried many answers (last six hours or so... too much to say here), the latest of which is using tokens, but that is not working. Here is what I have so far:
function jquizme_node_view($node, $view_mode, $langcode) {
switch ($node->type) {
case 'jquizme':
$items = field_get_items('node', $node, 'field_myfield', $node->language);
drupal_add_css(drupal_get_path('module', 'jquizme') . '/jQuizMe.css', >array('scope' => 'header'));
drupal_add_js(drupal_get_path('module', 'jquizme') . '/alert.js');
drupal_add_js(drupal_get_path('module', 'jquizme') . '/jQuizMe-2.2.js', >array('scope' => 'header'));
//drupal_add_js($tokens['node']['jquizme_js1_field'], array('scope' => >'header'));
//drupal_add_js($tokens['node']['jquizme_js2'], array('scope' => 'header'));
break;
}
}
Thanks in advance!
Can you try this?
// Let me assume that the field names of your two file fields
// are jquizme_js1_field and jquizme_js2_field for convenience..
function jquizme_node_view($node, $view_mode, $language) {
$items = field_get_items('node', $node, 'jquizme_js1_field');
_jquizme_add_js_from_filefield($items);
$items = field_get_items('node', $node, 'jquizme_js2_field');
_jquizme_add_js_from_filefield($items);
}
// Given the values of a filefield attached to some entity,
// adds them as JS files to the page.
function _jquizme_add_js_from_filefield($items = array()) {
foreach ($items as $item) {
$fid = &$item['fid'];
$file = file_load($fid);
if (!$file) {
continue; // Maybe the file got deleted..
}
$wrapper = file_stream_wrapper_get_instance_by_uri($file->uri);
$path = $wrapper->realpath();
// Ensure that the path exists and that it is a Javascript file..
if (file_exists($path) && preg_match('\.js$', $path)) {
drupal_add_js($path, array('type' => 'file'));
}
}
}

Drupal 7 Views Contextual Filters Title Override

I have a view that returns search results via the search API. It performs this use case adequately and I am happy. To crown the deliverable, I need to add a title override of the form Showing search results for '%1' which looks easy enough initially but it isn't working entirely as planned.
For a URL = mysite.com/search/all?search=wombat, where the search value is gathered from an exposed form within a block, I am either getting:
Showing search results for 'Search for "all"'
or, if I enter %1 in the title override for subject not appearing in the URL, I get:
Showing search results for %1". My goal is to get "Showing search results for 'wombat'
The title override works in that it removes the Search for ... part but the substitution picks up on "all" as the exception value (or anything else that I set as the exception value) where I need to be able to pick up the value of the query string (search=wombat).
Can anyone shed some light here?
The problem is that the '%1' and '%2' that you can use to override the title refer to your path's first and second arguments (in Drupal terms) and that would be 'search' and 'all?search=wombat' in your case...
What you need instead is the 'wombat' as a path component in itself.
Perhaps you can achieve that by working that case you're talking about: the case of a "title override for subject not appearing in the URL". There is an option in the contextual filters section (I'm assuming that's where you're working) for providing a default value when one isn't present. Perhaps you can use the 'PHP code' option there, isolate your 'wombat' string and return that as a default contextual filter, and then you can get to it via the '%1'.
The php code to get that portion of the URL should look something like this:
return htmlentities($_GET['search']);
the $_GET() returns the value of that variable in the url, and the htmlentities() is just to keep it safe, since it's using a portion of the url, which is vulnerable to XSS.
See if that combo (1) setting a default argument when one isn't present and 2) using that newly set argument in your title printout) works!
I fixed this issue.
Using following two hooks we can change the defalut value of filter Programmatically.
<?php
/**
* hook_views_pre_view
* #param type $view
* #param type $display_id
* #param type $args
*/
function MODULE_NAME_views_pre_view(&$view, &$display_id, &$args) {
if ($view->name == 'VIEW_NAME') {
$filters = $view->display_handler->get_option('filters');
$view->display_handler->override_option('filters', $filters);
}
}
/**
* hook__views_pre_build
* #param type $view
* #return type
*/
function MODULE_NAME_views_pre_build($view) {
if ($view->name=='VIEW_NAME') {
$view->display['page']->handler->handlers['filter']['filter_field']->value['value'] = 8;
return $view;
}
}
?>
This code worked for me. I am using the drupal 7.

how to force drupal function to not use DB cache?

i have a module and i am using node_load(array('nid' => arg(1)));
now the problem is that this function keep getting its data for node_load from DB cache.
how can i force this function to not use DB cache?
Example
my link is http://mydomain.com/node/344983
now:
$node=node_load(array('nid'=>arg(1)),null,true);
echo $node->nid . " -- " arg(1);
output
435632 -- 435632
which is a randomly node id (available on the system)
and everytime i ctrl+F5 my browser i get new nid!!
Thanks for your help
Where are you calling this? For example, are you using it as part of your template.php file, as part of a page, or as an external module?
Unless you have this wrapped in a function with its own namespace, try naming the variable differently than $node -- for example, name it $my_node. Depending on the context, the 'node' name is very likely to be accessed and modified by Drupal core and other modules.
If this is happening inside of a function, try the following and let me know what the output is:
$test_node_1 = node_load(344983); // Any hard-coded $nid that actually exists
echo $test_node_1->nid;
$test_node_2 = node_load(arg(1)); // Consider using hook_menu loaders instead of arg() in the future, but that's another discussion
echo $test_node_2->nid;
$test_node_3 = menu_get_object(); // Another method that is better than arg()
echo $test_node_3->nid;
Edit:
Since you're using hook_block, I think I see your problem -- the block itself is being cached, not the node.
Try setting BLOCK_NO_CACHE or BLOCK_CACHE_PER_PAGE in hook_block, per the documentation at http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_block/6
You should also try to avoid arg() whenever possible -- it's a little bit of a security risk, and there are better ways to accomplish just about anything arg() would do in a module environment.
Edit:*
Some sample code that shows what I'm referring to:
function foo_block ($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0] = array(
'info' => 'I am a block!',
'status' => 1,
'cache' => BLOCK_NO_CACHE // Add this line
);
return $block;
case 'view':
.....
}
}
node_load uses db_query, which uses mysql_query -- so there's no way to easily change the database's cache through that function.
But, node_load does use Drupal's static $nodes cache -- It's possible that this is your problem instead of the database's cache. You can have node_load clear that cache by calling node_load with $reset = TRUE (node_load($nid, NULL, TRUE).
Full documentation is on the node_load manual page at http://api.drupal.org/api/drupal/modules--node--node.module/function/node_load/6
I have had luck passing in the node id to node_load not in an array.
node_load(1);
According to Druapl's api this is acceptable and it looks like if you pass in an array as the first variable it's loaded as an array of conditions to match against in the database query.
The issue is not with arg(), your issue is that you have caching enabled for anonymous users.
You can switch off caching, or you can exclude your module's menu items from the cache with the cache exclude module.
edit: As you've now explained that this is a block, you can use BLOCK_NO_CACHE in hook_block to exclude your block from the block cache.

Resources