backdrop cms module-created blocks deltas not working - module

(tagging with drupal7 because i cannot create a tag for backdrop)
i have a fresh backdrop install, with a new theme duped from bartik, and a new layout duped from moscone_flipped. no code changes to those yet.
i have a module that creates 2 simple blocks, mostly just some html. i have implemented hook_block_info() and hook_block_view(). i can place blocks into regions in the layout using the admin ui. i can see each block on the front end page when i place either one of them. but not both. when i have both blocks placed in the layout, for some reason both regions display the output from the same block. and i have verified that it is always the first block defined in the array returned from hook_block_info(). i have cleared caches, checked code, etc.
has anyone seen this before?
btw, i just applied the recent security upgrade, and the behavior is the same both before and after the upgrade.
i will paste in the module code below, in case i have missed something.
thanks for any help anyone can provide.
// implements hook_block_info()
function mbr_block_info()
{
$info = array();
$info['rate-tables'] = array(
'info' => 'Rate Tables (Buttons)',
'description' => 'The displays the rate table links for the sidebar',
);
$info['mbr-footer'] = array(
'info' => 'MBR Footer',
'description' => 'Displays footer links, disclaimer, copyright',
);
return($info);
}
// implements hook_block_view()
function mbr_block_view($delta = '', $settings = array(), $contexts = array())
{
$block = array();
switch($delta)
{
case 'mbr-footer':
$subject = null;
$mbrFooter = getMBRFooterBlock();
$block = array('subject' => $subject, 'content' => $mbrFooter);
case 'rate-tables':
$subject = null;
$rateTables = getRateTablesBlock();
$block = array('subject' => $subject, 'content' => $rateTables);
}
return($block);
}

Related

Testing updating user profile data

I make http tests in my Laravel 5.7 application with profile page(which has "Profile View" page and "Profile Details" editor ), like :
$newUser->save();
$testing_user_id = $newUser->id;
$newUserGroup = new UserGroup();
$newUserGroup->group_id = USER_ACCESS_USER;
$newUserGroup->user_id = $newUser->id;
$userGroup= Group::find($newUserGroup->group_id);
$newUserSessionData = [
[
'loggedUserAccessGroups' => ['group_id' => $newUserGroup->group_id, 'group_name' => !empty($userGroup) ? $userGroup->name : ''],
'logged_user_ip' => '0',
]
];
$newUserGroup->save();
// 3. OPEN PROFILE PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('/profile/view');
// 3. OPEN PROFILE PAGE BLOCK END
// 4. MAKING CHECKING PROFILE FOR USER CREATED AT 2) BLOCK START
$response->assertStatus(200); // to use HTTP_RESPONSE_OK
$response->assertSee(htmlspecialchars("Profile : " . $newUser->username, ENT_QUOTES));
// 4. MAKING CHECKING PROFILE FOR USER CREATED AT 2) BLOCK END
// 5. OPEN PROFILE DETAILS VIEW PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/view');
$response->assertStatus(200);
$response->assertSee(htmlspecialchars("Profile : " . $newUser->username, ENT_QUOTES));
// 5. OPEN PROFILE DETAILS VIEW PAGE BLOCK END
// 6. OPEN PROFILE DETAILS EDITOR PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/edit-details'); // http://local-votes.com/profile/edit-details
$response->assertStatus(HTTP_RESPONSE_OK);
$response->assertSee(htmlspecialchars("Profile : Details"));
// 6. OPEN PROFILE DETAILS EDITOR PAGE BLOCK END
// 7. MODIFY PROFILE DETAILS PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->post('profile/edit-details-post', [
'first_name' => 'Modified : ' . $newUser->first_name,
'last_name' => 'Modified : ' . $newUser->last_name,
'phone' => 'Modified : ' . $newUser->phone,
'website' => 'Modified : ' . $newUser->website,
'_token' => $csrf_token
]);
// $response->assertStatus(205); // ???
// 7. MODIFY PROFILE DETAILS PAGE BLOCK END
////////////////////////
// 8. OPEN PROFILE DETAILS VIEW PAGE AFTER MODIFICATIONS BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/view');
$response->assertStatus(200);
$response->assertSee( htmlspecialchars('Modified : ' . $newUser->last_name) );
// 8. OPEN PROFILE DETAILS VIEW PAGE AFTER MODIFICATIONS BLOCK END
New user is added and Profile View page is opened ok, but there are problems at step // 7. MODIFY PROFILE DETAILS PAGE BLOCK START
as I see in sql trace new user is inserted but not updated.
In my control app/Http/Controllers/ProfileController.php update method is defined with validation request :
public function update_details(ProfileUserDetailsRequest $request)
{
$userProfile = Auth::user();
$requestData = $request->all();
$userProfile->first_name = $requestData['first_name'];
$userProfile->last_name = $requestData['last_name'];
$userProfile->phone = $requestData['phone'];
$userProfile->website = $requestData['website'];
$userProfile->updated_at = now();
$userProfile->save();
$this->setFlashMessage('Profile updated successfully !', 'success', 'Profile');
return Redirect::route('profile-view');
} // public function update_details(ProfileUserDetailsRequest $request)
1) Can the reason be in ProfileUserDetailsRequest and how to deal this ?
My profile details editor works ok.
My route defined as :
Route::group(array('prefix' => 'profile', 'middleware' => ['auth', 'isVerified']), function(){
Route::post('edit-details-post', array(
'as' => 'profile-edit-details-post',
'uses' => 'ProfileController#update_details'
));
At first I tried PUT, but after that I tried POST - the same without results.
2) Can you advice some proper way of User Profile details checking on // 7. MODIFY PROFILE DETAILS PAGE BLOCK START step ?
MODIFIED BLOCK # 2 :
I tried patch method, but it does not work anyway.
I have debugging method in my app/Http/Controllers/ProfileController.php
public function update_details(ProfileUserDetailsRequest $request)
{
method and when test is run I see that it is not triggered.
I use the same update_details method updating my form in brauser and it work ok(I see debugging info too).
I suppose that could be csrf issue and in header of my test file I wrote:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use DB;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\WithoutMiddleware; // Prevent all middleware from being executed for this test class.
public function testProfilePage()
{
$csrf_token = csrf_token();
...
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->patch('profile/edit-details-post', [
'first_name' => 'Modified : ' . $newUser->first_name,
'last_name' => 'Modified : ' . $newUser->last_name,
'phone' => 'Modified : ' . $newUser->phone,
'website' => 'Modified : ' . $newUser->website,
// '_token' => $csrf_token / I TRIED TO UNCOMMENT THIS LINE TOO
]);
$response->assertStatus(205); // making this check I see that code 419 was returned
Can decision be to add in file app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
// ???
];
If in command line I run tests as
vendor/bin/phpunit tests/Feature/ProfilepageTest.php
What have I to add in except?
Thanks!
Other than the PATCH instead of POST following are my recommendations to test your code.
Instead of ProfileUserDetailsRequest try to use simple Request.
Try to log $request variable in your update function and check if the _token and _method are available, method should be PATCH and the request variables are posted correctly.
Make a model of user table and try to update the user with that model using
$user = User::find(Auth::user()->id);
…
$user->save();
Sessions are initiated with a middleware, i think if you are disabling the middleware, session will not work.
If you are using an IDE like Visual Studio Code to run your code then try using a debugger like xdebug. Place a breakpoint in your update_details method and see if it is getting to save and save is executing. If it is then we know save is not updating correctly.
It looks like what you are doing is correct according to the documentation for update:
https://laravel.com/docs/5.7/eloquent#updates example from docs below:
$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save();
Off the top of my head my only guess as to why it would fail is maybe getting the user off of the auth object causes problems. Take the id from the user in the auth object and use find() to grab the user then update its values and save and see if that works.

how to integrate multimodelform with echmultiselect yii?

I am running into a little snag with combining extensions "EchMultiSelect" and "MultiModelForm" of YII framework.
What I'm trying to do is copy a set of form elements one of which elements is an EchMultiSelect widget.
According to tutorial on the jqRelCopy page, I would need to pass a copy of the element (datePicker in their example) to the 'jsAfterNewId' option:
'jsAfterNewId' => JQRelcopy::afterNewIdDatePicker($datePickerConfig),
So, I tried to modify that to:
'jsAfterNewId' => MultiModelForm::afterNewIdMultiSelect($memberFormConfig['elements']),
Where I also added the following to MultiModelForm.php:
public static function afterNewIdMultiSelect($element)
{
$options = isset($element['options']) ? $element['options'] : array();
$jsOptions = CJavaScript::encode($options);
return "if(this.attr('multiple')=='multiple'){this.multiselect(jQuery.extend({$jsOptions}));};";
}
its copied and working properly when i am using Add Person link but what happens if i am adding/cloning three items for example and when i change the third item multiselct option then its reflecting to the first multiselect dropdown only this is same for other as well also when i am adding new items by clicking on the Add Person link then its cloning the same element to the new row item
here is the code for the form configuration variables and multimodel widget call.
//$userList=array of the userIds from users table
$memberFormConfig = array(
'elements'=>array(
'userId'=>array(
'type'=>'ext.EchMultiSelect.EchMultiSelect',
'model' => $User,
'dropDownAttribute' => 'userId',
'data' => $userList,
'dropDownHtmlOptions'=> array(
'style'=>'width:500px;',
),
),
...
...
));
calling the MultiModelForm widget from the same view file
$this->widget('ext.multimodelform.MultiModelForm',array(
'id' => 'id_member', //the unique widget id
'formConfig' => $memberFormConfig, //the form configuration array
'model' => $model, //instance of the form model
'tableView' => true,
'validatedItems' => $validatedMembers,
'data' => Person::model()->findAll('userId=:userId', array(':userId'=>$model->id)),
'addItemText' => 'Add Person',
'showAddItemOnError' => false, //not allow add items when in validation error mode (default = true)
'fieldsetWrapper' => array('tag' => 'div',
'htmlOptions' => array('class' => 'view','style'=>'position:relative;background:#EFEFEF;')
),
'removeLinkWrapper' => array('tag' => 'div',
'htmlOptions' => array('style'=>'position:absolute; top:1em; right:1em;')
),
'jsAfterNewId' => MultiModelForm::afterNewIdMultiSelect($memberFormConfig['elements']),
));
Can someone help me with this please?
Thanks in advance!
After a long searching and googleing i found the solution for this, just replace the function in your MultiModelForm.php:
public static function afterNewIdMultiSelect($element)
{
$options = isset($element['options']) ? $element['options'] : array();
$jsOptions = CJavaScript::encode($options);
return "if ( this.hasClass('test123456') )
{
var mmfComboBoxParent = this.parent();
// cloning autocomplete and select elements (without data and events)
var mmfComboBoxClone = this.clone();
var mmfComboSelectClone = this.prev().clone();
// removing old combobox
mmfComboBoxParent.empty();
// addind new cloden elements ()
mmfComboBoxParent.append(mmfComboSelectClone);
mmfComboBoxParent.append(mmfComboBoxClone);
// re-init autocomplete with default options
mmfComboBoxClone.multiselect(jQuery.extend({$jsOptions}));
}";
}
Thats It....!!
Thanks...!!!

Yii : Multiple activeCheckboxlist with same model

has just started out Yii web app and encountered this problem, any suggestions are welcome:)
What i am trying to achieve:
-To display a form with tabs, each tab content contains a list of checkboxes from the same model.
-so user can select some items from tab 1, some from tab 2, etc and then click submit button to process.
Problem:
But i couldn't think of anyway such that the last tab activecheckboxlist will not clobbered the previous one up.
I am trying to to something similar to this : [www.yiiframework.com/forum/index.php/topic/20388-2-checkboxlist-and-1-model]
but instead of fixing it at 2, mine is dynamic.
What i have done so far:
<?php
$tabArray = array();
foreach ((Product::model()->listParentChild(0)) as $productparent) {
array_push($tabArray, array(
'label' => $productparent['name'],
'content' => CHtml::activeCheckBoxList(
$model, 'products', CHtml::listData(Product::model()->listParentChild($productparent['id']), 'id', 'name'), array(
'labelOptions' => array('style' => 'display:inline'),
'template' => '<div class="check-option">{input} {label}</div>',
'separator' => '',
)
), 'active' => ($productparent['id'] == 1 ? true : false),
));
}
?>
<?php
$this->widget('bootstrap.widgets.TbTabs', array(
'type' => 'tabs', // 'tabs' or 'pills'
'placement' => 'left',
'tabs' => $tabArray,
));
?>
and in my product model:
public function listParentChild($parentid) {
$sql = "SELECT * FROM piki_product WHERE parentid=:parentid";
$productlist = Yii::app()->db->createCommand($sql);
$productlist->bindValue(":parentid", $parentid, PDO::PARAM_INT);
return $productlist->queryAll();
}
any suggestions will be appreciated.. :/
I could be wrong, but I don't think cliffbarnes is on the right track with his comments about dynamic nesting. As far as I can tell, you're only dealing with one level of child products; it's just that there could be multiple sets of these child products.
In that case, the link you sited actually offers the correct solution:
<?php echo CHtml::checkBoxList('array1', CHtml::listData(Atributos::model()-> findAllByAttributes(array('tipo'=>'talla')), 'id_atributo','valor'))?>
<?php echo CHtml::checkBoxList('array2', CHtml::listData(Atributos::model()-> findAllByAttributes(array('tipo'=>'talla')), 'id_atributo','valor'))?>
Each set of checkboxes is given a different name (array1, and array2), so that each field's selected values doesn't override the other. In your case, the solution is the same; you just need to make the field names dynamic. I.E.
foreach ((Product::model()->listParentChild(0)) as $productparent) {
$fieldname = 'product' . $productparent['id'];
echo CHtml::checkBoxList($fieldname, ... (etc)
Within your controller you would check to see whether there are results for each dynamic field name.
foreach ((Product::model()->listParentChild(0)) as $productparent) {
if (isset($_POST['product' . $productparent['id']]) {
// Add values to $model->product
}
}
An even better solution would be to output each checkbox individually, so you can create one array of results, indexed by child ID.
foreach ((Product::model()->listParentChild(0)) as $productparent) {
foreach (Product::model()->listParentChild($productparent['id']) as $child) {
CHtml::checkBox("product[{$child['id']}]", ... (etc)
Then in your controller, all you'd have to do is this:
if (isset($_POST['product']) && count($_POST['product']) > 0) {
$model->product = array_keys($_POST['product']);
}
This solution does not work with activeCheckBoxList(). It would work if you wanted to override the __get() and __set() magic methods to make these dynamic property names available to your model, but that's probably over kill.
Edit (as per request)
If you need to have default selections for your checkboxes, you can just pass them as the second argument of CHtml::checkBoxList(). http://www.yiiframework.com/doc/api/1.1/CHtml#checkBoxList-detail
But if you still want to use __get() and __set(), here's an example:
class YourModel extends CActiveRecord {
// I usually create a placeholder to contain the values of my virtual attribute
protected $_childValues = array();
public function __get($name) {
// The following regular expression finds attributes
// with the name product_{parent ID}
if (preg_match("/^product_\d+$/", $name)) {
// I put the underscore in the name so I could get
// parent ID easier.
list($junk, $id) = explode("_", $name);
if (!isset($this->_childValues[$id])) {
$this->_childValues[$id] = array();
}
return $this->_childValues[$id];
}
else {
// Make sure to still call the parent's __get() method
return parent::__get($name);
}
}
public function __set($name, $value) {
// Same regex as above
if (preg_match("/^product_\d+$/", $name)) {
list($junk, $id) = explode("_", $name);
$this->_childValues[$id] = $value;
}
else {
// Make sure to still call the parent's __set() method
parent::__set($name, $value);
}
}
}
$model = new YourModel;
// Any property in the format of product_{parent ID} is available
// through your model.
echo $model->product_1;
$model->product_300 = array();
You might also consider checking to see if the parent ID in a property name corresponds with a parent ID in the database, instead of just allowing any property in that format to pass through.

Multiple languages in cakephp issue - can't get login to work

I followed this tutorial to create multilingual site.
http://nuts-and-bolts-of-cakephp.com/2008/11/28/cakephp-url-based-language-switching-for-i18n-and-l10n-internationalization-and-localization/
However although I can get to the login page at example.com/en/users/login when i try to login, the login wouldn't go through. I get thrown at example.com/users/login without the /en/ and I don't know if this matters, but the password does not contain 4 letters/stars/dots like the password i tried, but about 40.
Also, I noticed that the example.com/en/users/logout function does work to log me out, but takes me to example.com/users/login instead of example.com/en/users/logout
I managed to get to the fact that the function that breaks it is the:
class AppHelper extends Helper {
function url($url = null, $full = false) {
if(!isset($url['language']) && isset($this->params['language'])) {
$url['language'] = $this->params['language'];
}
return parent::url($url, $full);
}
}
However, without it, no urls work at all in terms of the /en/ addition in the URL.
Can anyone help? I will provide any code needed.
This was quite a journey to make it work. Some of the things I still don't get, but at least I know they work. If you make an improvement on this let me know, I'd like to be aware of it.
This tutorial in the question only gets you half way.
In addition, here are a few things that need to be moded to get this working:
Routes.php:
/**
* LANGUAGES
*/
Router::connect( '/:language/:plugin/:controller/:action/*', array(), array('language' => '[a-z]{3}')); // PLUGIN FIX
Router::connect('/:language/:controller/:action/*', array('plugin' => null), array('language' => '[a-z]{3}'));
Router::connect('/:language', array('controller'=>'static', 'plugin'=>null), array('language' => '[a-z]{3}'));
App_controller.php:
function beforeFilter(){
$this->_setLanguage();
$this->Auth->logoutRedirect = array( 'controller' => 'static', 'action' => 'index', 'language'=>$this->Session->read('Config.language'));
$this->Auth->loginRedirect = array( 'controller' => 'static', 'action' => 'dashboard', 'language'=>$this->Session->read('Config.language'));
$this->Auth->loginAction = array( 'controller'=>'users', 'action'=>'login', 'language'=>$this->Session->read('Config.language'));
}
function _setLanguage() {
if ($this->Cookie->read('lang') && !$this->Session->check('Config.language')) {
// If ... don't really get this.
$this->Session->write('Config.language', $this->Cookie->read('lang'));
}
else if (isset($this->params['language']) && ($this->params['language']
!= $this->Session->read('Config.language'))) {
// Had a language set, but different from the one in the URL, set to URL
$this->Session->write('Config.language', $this->params['language']);
$this->Cookie->write('lang',$this->params['language'], false, '360 days');
}else{
// First time comer
$this->Session->write('Config.language', Configure::read('Config.language' ));
$this->Cookie->write('lang', Configure::read('Config.language' ), false, '360 days');
}
}
function redirect( $url, $status = NULL, $exit = true ) {
if (!isset($url['language']) && $this->Session->check('Config.language')) {
$url['language'] = $this->Session->read('Config.language');
}
parent::redirect($url,$status,$exit);
}
app_helper.php:
function url($url = null, $full = false) {
if(!isset($url['language']) && isset($this->params['language'])) {
$url['language'] = $this->params['language'];
}else if (!isset($url['language']) && !isset($this->params['language'])){
if($_COOKIE['lang']){
$url['language'] = $_COOKIE['lang'];
}else{
$url['language'] = Configure::read('Config.language');
}
}
return parent::url($url, $full);
}
And this should be it. Hope that helps all of you lost souls with multilingual cakephp stuff
pp
I used the same resource to make cakephp multilingual, but today got stuck with that problem that by default login action loses language. When I found this post, the only thing that I need in addition to the original manual is the following code in controller_app.php beforeFilter:
$this->Auth->logoutRedirect = array( 'language'=>$this->Session->read('Config.language'));
$this->Auth->loginRedirect = array( 'language'=>$this->Session->read('Config.language'));
$this->Auth->loginAction = array( 'controller'=>'users', 'action'=>'login', 'language'=>$this->Session->read('Config.language'));
I saw your other question about multilingual setting. I was going to say that just make the default language to be 'en'. But I'm uncertain how that would affect SEO, so I didn't say anything. But yeah, the way you are doing right now might interfere with many Cake automagic, like the Auth problem you are having.
Here what I'd suggest: In app_controller:
function beforeFilter(){
$this->Auth->loginAction = array(
'controller' => 'users',
'action' => 'login' // insert the language option that you use here
);
$this->Auth->logoutRedirect = array(
'controller' => 'users',
'action' => 'index'
);// you can set where to redirect after logout here
}
I would advise not to redirect to /users/logout, unless you want to do something there. And you would need to change the logout function in users_controller too.
One thing that helped me, (not perfect but it's a start)
is i created exceptions for the 'loginPage' (the login action for the auto component)
so the language of the url doesn't get populated when logging in.
this helped me as i wasn't able to login until i did this
i added this to the app_helper.php
> //exceptions to allow to login
> if (isset($url['action'])) {
> if ($url['action'] == 'loginPage') $url['language'] = false;
> }

Symfony file upload - "Array" stored in database instead of the actual filename

I'm using Symfony 1.4.4 and Doctrine and I need to upload an image on the server.
I've done that hundreds of times without any problem but this time something weird happens : instead of the filename being stored in the database, I find the string "Array".
Here's what I'm doing:
In my Form:
$this->useFields(array('filename'));
$this->embedI18n(sfConfig::get('app_cultures'));
$this->widgetSchema['filename'] = new sfWidgetFormInputFileEditable(array(
'file_src' => '/uploads/flash/'.$this->getObject()->getFilename(),
'is_image' => true,
'edit_mode' => !$this->isNew(),
'template' => '<div id="">%file%</div><div id=""><h3 class="">change picture</h3>%input%</div>',
));
$this->setValidator['filename'] = new sfValidatorFile(array(
'mime_types' => 'web_images',
'path' => sfConfig::get('sf_upload_dir').'/flash',
));
In my action:
public function executeIndex( sfWebRequest $request )
{
$this->flashContents = $this->page->getFlashContents();
$flash = new FlashContent();
$this->flashForm = new FlashContentForm($flash);
$this->processFlashContentForm($request, $this->flashForm);
}
protected function processFlashContentForm($request, $form)
{
if ( $form->isSubmitted( $request ) ) {
$form->bind( $request->getParameter( $form->getName() ), $request->getFiles( $form->getName() ) );
if ( $form->isValid() ) {
$form->save();
$this->getUser()->setFlash( 'notice', $form->isNew() ? 'Added.' : 'Updated.' );
$this->redirect( '#home' );
}
}
}
Before binding my parameters, everything's fine, $request->getFiles($form->getName()) returns my files.
But afterwards, $form->getValue('filename') returns the string "Array".
Did it happen to any of you guys or do you see anything wrong with my code?
Edit: I added the fact that I'm embedding another form, which may be the problem (see Form code above).
Alright, I got it. I wasn't properly declaring my validator.
What i should've done is:
$this->setValidator('filename', new sfValidatorFile(array(
'mime_types' => 'web_images',
'path' => sfConfig::get('sf_upload_dir').'/flash',
)));
Silly mistake, I hope that will help those who have the same problem.
Alternatively you can use;
$this->validatorSchema['filename']
in place of;
$this->setValidator['filename']