How programmatically disable blocks under drupal 7?
Refer to code below. Points to keep in mind are for best usage:
Block must already exist and be assigned to a region e.g "before_content"
After each disable/enable clear your cache "drush cc all"
On re-enable the block remembers it's position
Your block delta can be a number only or alpha numeric
Disable block:
db_update('block')
->fields(array(
'status' => 0,
'region' => 'disabled',
)
)
->condition('delta', 'client-block-number_here')
->execute();
Enable block:
db_update('block')
->fields(array(
'status' => 1,
'region' => 'before_content',
)
)
->condition('delta', 'client-block-number_here')
->execute();
The real reason is why would you want to disable block?
if you want to show a block depending on users, to do a db attack is not a good solution.
I think you can do that with region and preprocess system. A region can show anythings, blocks, text or nothing.
Example :
function HOOK_preprocess_node(&$variables, $hook){
//check the current user code...
//..
if (_condition_is_ok){
$block = module_invoke('module', 'block_view', 'block_name');
$variables["my_block"] = $block["content"];
}
}
If you do that dont forget to check the variable is set in your tpl :)
I don't think that the better way to do that but it's better than use db_update, db_update write directly in your db, and by pass the drupal engine.
Related
I ran into a bug while modifying a WordPress theme. The bug is that on Firefox, the page is scrollable to extremely many pixels, even though the actual website content is the proper size.
I also tried deleting both the parent and child themes, reinstalled them using the original zip files, but it doesn't work because the settings are actually saved in a database.
(I know this to be true because the custom color settings I chose reappear even after deleting and reinstalling the themes. If this is the case, does that mean the problem is not caused by my tampering with the CSS, but through a setting that is customizable from the WordPress customize interface?)
I haven't been able to find the code I tampered with manually, so I want to reset the database without resetting ALL the database settings. I just want to reset the database for the theme I tampered with.
How to reset the database for only a given theme, not the entire database?
Search for the following functions used in the theme:
add_option( 'option_name', $values );
update_option( 'option_name', $values );
Then search the database for option_name and delete the entries. If you are lucky, the theme uses only one entry and saves everything inside an array ($values). But there are themes that save each value inside one option, something like:
$values = array(
'color' => '#fff',
'background' => '#000',
'etc' => 'something',
// a hundred more options
);
$theme_prefix = 'superTheme_';
foreach( $values as $value => $default ) {
add_option( $theme_prefix . $value, $default );
}
I am using CakePHP in my project and I am looking for a proper way to check advanced user rights in my views.
I have several pages in which the contents depend of your rights (you can view some blocks or not, edit some infos or not, etc...)
I searched and the only way I found is to implement an Auth Helper, but I thought the best way to to that is to implement methods in my "UserController" (such as canPerformAction($action, $controller = 'default_controller')), am I wrong ? And if I'm right, how to call that methods properly ?
Thanks.
EDIT : More precisions
For example I have an action "editEventProducts" that a user can perform only if he's the event owner and if the event status is <= 2.
I check that in my controller "isAuthorized" function, works like a charm.
But I have a page called "eventDetails", form which you can perfom several actions such as this one, and I want to show the edit button, only if you can do it.
If fact what I need is the output of the "isAuthorized" function for each action that you can call, but can I properly get it from a view ?
Solution
I implemented a Auth helper who does several check such as this one, which is finally a whitelist check, depending of the status of my event, hope it will help, the code :
App::uses('AppHelper', 'View/Helper');
class AuthHelper extends AppHelper {
var $helpers = array('Session');
private $_whitelist = array(
'controller1' => array(
'events' => array(
'action1' => array(1 => true, 2 => true),
'action2' => array(1 => true, 2 => true),
'action3' => array(3 => true),
'action4' => array(6 => true)
)
),
'user' => array(
'controller1' => array(
'action1' => array(1 => true, 2 => true),
'action2' => array(1 => true, 2 => true)
)
)
);
public function canPerformAction ($action, $event_infos, $controller = 'events') {
return isset($this->_whitelist[$this->Session->read('Auth.User.role')][$controller][$action][$event_infos['Event']['state_id']]);
}
}
It sounds to me like you just want to render some parts of a view based on the permissions of the user. Well, in this case I think a helper is the right choice. The user should already have all the permissions he has loaded - except they're very fine grained and you got thousands of permissions.
Check this AuthHelper, it allows you to check if the user is logged in, for a role or a set of roles in a field. Alternatively implement your own solution to match whatever your permission system is.
Note that the helper relies on passing the user data to the view in a view variable. It can be also configured to read the data from the auth part of the session directly.
Here is the example taken from it's documentation:
if ($this->Auth->isLoggedIn()) {
echo __('Hello %s!', $this->Auth->user('username'));
}
if ($this->Auth->isMe($record['Record']['user_id']) {
// or your edit button here
echo '<h2>' . __('Your records') . '</h2>';
}
if ($this->Auth->hasRole('admin') {
echo $this->Html->link(__('delete'), array('action' => 'delete'));
}
What you need is called authorization, and is the process of granting/denying actions usually built on top of an authentication step, which maps HTTP requests to logical users.
The authorization scheme can be implemented in a number of ways, for example with simple role-based rules, where users are grouped exactly for the purpose of assigning rights, or with more complex ACL (access control lists). Both can be adopted at the same time for different parts of the system, depending on your needs.
Whatever scheme you pick, you absolutely need to query it at the beginning of your controllers actions (if applicable, you may and up with a standardized authorization filter in your AppController), because the HTTP request doesn't need to come from a previously sent HTTP page, but could be a (possibly) malicious, hand-craften one. Also, you'll likely need to adjust the UI after the user rights. Maybe you'll better start with a bunch of if statements, and then after some days of work you'll be able to identify your needs and build your libraries/helpers/blocks/whatever to avoid code duplication and easing reading the templates.
If you have predefined user permissions (like 'admin', 'moderator', 'editor', 'publisher'...) you can just read the user role and current action in the controller function isAuthorized and set it to true or false.
If you want custom permissions per user, you can store those values in the database, read them in the isAuthorized function and make your logic to determine if you should allow him or not.
My solution to this was a separate table user_permissions that was something like this:
user_id | action
where action would be `controller/action' or 'view/block' or whatever you want to save there.
I would read all values for current user in the controller and if the current controller/action was found in the array, i'd set isAuthorized to true. You can apply your logic to the blocks also.
You can call function of controller from view using
requestAction(string $url, array $options)
Or you can create your custom Helper which will do this for you!
I'm trying to simply perform the following via Cake's save() function.
UPDATE user SET value = value-1
However, it seems it can only set. It will not understand anything I pass to it to increment or subtract, and no one on the internet seems to be having this issue. :P Even when going through a full piece of software someone built on CakePHP 2.0, I'm finding $this->query() used for updating by increments! Is this really how I'll update if I don't already have the value to be setting?
(code appears as follows)
$data = array('id' => uid, 'value' => "Users.value = Users.value - 1");
$this->User->save($data);
The code for producing an increment or decrement in CakePHP database is as follows:
$this->User->updateAll(array('value' => 'value - 1'), array('id' => uid));
Arun's answer was not correct; you must put the - 1 within quotes to get Cake to recognize it is part of the query. Else it will try to set all User.value to -1. Note that you must put the information (identifiers) of the columns that you want to update on in the second condition.
basically you just have to use updateAll for atomic queries like this
$this->User->updateAll($fields, $conditions);
http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-updateall-array-fields-array-conditions
You can do so using following query:
$this->User->updateAll(array('User.value' => 'User.value' - 1));
//or
//$this->User->updateAll(array('User.value' => 'User.value' - 1), array('User.id' => $uid));
I have a songs controller. Within the songs controller i have a 'view' action which get's passed an id, eg
/songs/view/1
/songs/view/5
/songs/view/500
When a user visits /songs/view/1, the file is cached correctly and saved as 'songs_view_1.php'
Now for the problem, when a user hit's a different song, eg /songs/view/2, the 'songs_view_1.php' is deleted and '/songs/view/2.php' is in it's place.
The cahced files will stay there for a day if I don't visit a different url, and visiting a different action will not affect any other action's cached file.
I've tried replacing my 'cake' folder (from 1.2 to 1.2.6), but that didn't do anything. I get no error messages at all and nothing in the logs.
Here's my code, I've tried umpteen variations all ending up with the same problem.
var $helpers = array('Cache');
var $cacheAction = array(
'view/' => '+1 day'
);
Any ideas?
EDIT:
After some more testing, this code
var $cacheAction = array(
'view/1' => "1 day",
'view/2' => "1 day"
);
will cache 'view/1' or 'view/2', but delete the previous page as before. If I visit '/view/3' it will delete the cached page from before... sigh
EDIT:
Having the same issue on another server with same code...
After working hours on this, I finally figure out the reason why the cache keep being deleted, the REASON is because you had some operations that update your 'song' record in the database after you view the 'song'. For my case, I keep a column in my database called 'Hits' to store the number of hits/reads, and it updates it everytime it read the record.
Cakephp has a feature to aumotically detect changes to your database and clear the cache for you.
Try remove any operations that update your 'song' record and the cacheaction should be working properly.
An alternative is to redefine the clearcache function in your 'song' model... it will disable the function to auto-clear off the cache.. but then remember to manually clear the cache yourself when an update is performed.
function _clearCache($type = null) {
}
After working hours on this, I finally figured out the reason why the cache keeps on being deleted. The reason is because you had some operations that update your 'song' record in the database after you view the 'song'. For my case, I keep a column in my database called 'Hits' to store the number of hits/reads, and it updates it everytime it read the record.
Cakephp has a feature to automatically detect changes to your database and clear the cache for you.
Try remove any operations that update your 'song' record and the cacheaction should work properly.
After fixing it, there will be another issue. Let's say you cache many of your records, for example song/1, song/5, song/100...etc, if there is any update for any 1 of the record... all of the caches for song/1, song/5, song/100 will be deleted. This makes cacheaction useless for frequently update website.
The solution to this is to redefine the clearcache function in your 'song' model... it will disable the function to auto-clear off the cache.. so if there is any update, none of the caches will be deleted. But then remember to manually clear the cache yourself when an update is performed.
function _clearCache($type = null) {
}
to remove cache manually, you could use
#unlink(CACHE.'views'.DS.'website_songs_view_50.php');
I think that kind of caching method is depreceted. Perhaps you should use Cache:
$song = Cache::read('songs/view/'.$id, 'cache_time');
if(empty($song)){
$song = $this->Song->findById($id);
Cache::write('songs/view/'.$id, $song, 'cache_time');
}
cache_time is a variable you define in core.php:
Cache::config('cache_time', array('engine' => 'File', 'duration' => 60*60*24));
Hope it helps.
Check some setting in the config.php file. Do you have the following setting enabled?
Configure::write('debug', 0);
//Configure::write('Cache.disable', true);
Configure::write('Cache.check', true);
Cache::config('default', array('engine' => 'File'));
I have a bunch of name/email fields in my form like this:
data[Friend][0][name]
data[Friend][1][name]
data[Friend][2][name]
etc.
and
data[Friend][0][email]
data[Friend][1][email]
data[Friend][2][email]
etc.
I have a custom validation rule on each one that checks to see if the corresponding field is filled in. Ie. if data[Friend][2][name] then data[Friend][2][email] MUST be filled in.
FYI, heres what one of the two rules look like:
My form validation rule: ( I have an email validation too but that's irrelevant here)
'name' => array(
'checkEmail' => array(
'rule' => 'hasEmail',
'message' => 'You must fill in the name field',
'last' => true
)
)
My custom rule code:
function hasEmail($data){
$name = array_values($data);
$name = $name[0];
if(strlen($name) == 0){
return empty($this->data['Friend']['email']);
}
return true;
}
I need to make it so that one of the pairs should be filled in as a minimum. It can be any as long as the indexes correspond.
I can't figure a way, as if I set the form rule to be required or allowEmpty false, it fails on ALL empty fields. How can I check for the existence of 1 pair and if present, carry on?
Also, I need to strip out all of the remaining empty [Friend] fields, so my saveAll() doesn't save a load of empty rows, but I think I can handle that part using extract in my controller. The main problem is this validation. Thanks.
I would have a look at the Model::beforeValidate callback (API).
Using this callback to output debug information should help you figure out how many times it fires and what data is available to the model on each call.
With this information, you could then create a flag when you find your first matching pair, and tamper with either the Model::validates array or the Model::data array to bypass subsequent validation attempts.
As for your last point, you may be able to use Set::filter to easily remove blank fields from your data set.