I have an odd error in a CakePHP 3 Application I am developing and I can't figure what the issue is.The application and issue is as follows:
I have a Wishlist
That Wishlist can have many Wishlist Items
I am using Angular/Ajax to make a call and delete a WishlistItem
http://domain.com/wishlist_items/delete/219
This does not work and it returns the following error:
array_merge(): Argument #2 is not an array
/vendor/cakephp/cakephp/src/ORM/Association/DependentDeleteTrait.php 54
The WishlistItemsController.php in question is:
public function delete($id = null) {
$this->autoRender = false;
$this->request->allowMethod(['post', 'delete']);
$wishlistItem = $this->WishlistItems->get($id);
if ($this->WishlistItems->delete($wishlistItem)) {
echo json_encode(['message' => ['type' => 'success', 'text' => 'This wishlist item has been deleted successfully']]);
}
else {
echo json_encode(['message' => ['type' => 'error', 'text' => 'This wishlist item could not be deleted']]);
}
return;
}
The Wishlist Items have no dependents and the error is coming from this file http://api.cakephp.org/3.0/source-class-Cake.ORM.Association.DependentDeleteTrait.html#19-57 line 54
My table files look like this:
WishlistsTable.php
$this->hasMany('WishlistItems', [
'foreignKey' => 'wishlist_id',
'dependent' => true,
'cascadeCallbacks' => true,
]);
==================================================
WishlistItemsTable.php
$this->addBehavior('Timestamp');
$this->addBehavior('Ratings.Ratable');
$this->belongsTo('Wishlists', [
'foreignKey' => 'wishlist_id'
]);
$this->addBehavior('CounterCache', [
'Wishlists' => ['items_count']
]);
I cannot understand why cascadeDelete function is being used when this Table does not have any dependents.
STACKSTRACE:
Whoops\Exception\ErrorException thrown with message "array_merge(): Argument #2 is not an array"
Stacktrace:
#15 Whoops\Exception\ErrorException in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/ORM/Association/DependentDeleteTrait.php:54
#14 Whoops\Run:handleError in /var/www/domain.com/dev/website/vendor/gourmet/whoops/src/Error/WhoopsHandler.php:27
#13 Gourmet\Whoops\Error\WhoopsHandler:_displayError in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php:139
#12 Cake\Error\BaseErrorHandler:handleError in <#unknown>:0
#11 array_merge in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/ORM/Association/DependentDeleteTrait.php:54
#10 Cake\ORM\Association\HasMany:cascadeDelete in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php:273
#9 Cake\ORM\AssociationCollection:cascadeDelete in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/ORM/Table.php:1705
#8 Cake\ORM\Table:_processDelete in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/ORM/Table.php:1643
#7 Cake\ORM\Table:Cake\ORM\{closure} in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/Database/Connection.php:557
#6 Cake\Database\Connection:transactional in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/ORM/Table.php:1648
#5 Cake\ORM\Table:delete in /var/www/domain.com/dev/website/src/Controller/WishlistItemsController.php:139
#4 App\Controller\WishlistItemsController:delete in <#unknown>:0
#3 call_user_func_array in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/Controller/Controller.php:429
#2 Cake\Controller\Controller:invokeAction in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/Routing/Dispatcher.php:114
#1 Cake\Routing\Dispatcher:_invoke in /var/www/domain.com/dev/website/vendor/cakephp/cakephp/src/Routing/Dispatcher.php:87
#0 Cake\Routing\Dispatcher:dispatch in /var/www/domain.com/dev/website/webroot/index.php:37
If there were really only BelongsTo associations on the table object where you are calling delete(), then such a control flow should never happen, so there need to be more associations defined from elsewhere.
Given that the Ratings.Ratable behavior belongs to dereuromark/cakephp-ratings, I'd suspect that the problem are the conditions that are being defined for the HasMany association that the behavior adds to the table:
https://github.com/dereuromark/cakephp-ratings/.../Behavior/RatableBehavior.php#L85
$this->_table->hasMany('Ratings', [
'className' => $this->_config['rateClass'],
'foreignKey' => $this->_config['foreignKey'],
'unique' => true,
'conditions' => '', // <<<<<< There it is
'fields' => '',
'dependent' => true,
//'table' => 'sandbox_ratings'
]
);
That value ends up being passed to array_merge() as the second argument in DependentDeleteTrait::cascadeDelete(), hence the error.
So, that's a bug in the plugin, and I'd suggest that you report it. As a quick workaround, you could overwrite the conditions in your table class, like
$this->association('Ratings')->conditions([]);
Related
The site is on a php5.6 server - shared hosting so installation is done manually using github and php-download.com.
We've chosen to use mpdf and I can create test files by calling it directly.
Our cake site is v3.x.
I've added the pdf extension to routes.php
I've added this to bootstrap.php
Plugin::load('CakePdf',['bootstrap' => true]);
Configure::write('CakePdf', [
'engine' => 'CakePdf.MpdfEngine',
'margin' => [
'bottom' => 15,
'left' => 50,
'right' => 30,
'top' => 45
],
'orientation' => 'portrait',
'download' => true
]);
In my "forms" controller I have 2 functions - they both throw errors on the homepage.
//before the class
use CakePdf\Pdf\CakePdf;
//in the class
function test(){
$this->viewBuilder()->setClassName('CakePdf.Pdf');
$this->viewBuilder()->setLayout('default');
$this->viewBuilder()->options([
'pdfConfig' => [
'engine' => 'CakePdf.MpdfEngine',
'download' => true,
'title' => 'My Form',
'filename' => 'Form1.pdf'
]
]);
}
function test1(){
$pdf_path = WWW_ROOT . 'tmp/tests/'.date('Y-m-d') . DS . 'test1.pdf';
//$CakePdf = new CakePdf();
$CakePdf = new \CakePdf\Pdf\CakePdf\CakePdf();
debug($CakePdf);
exit;
$CakePdf->template('test', 'pdf/default');
$pdf = $CakePdf->output();
$pdf = $CakePdf->write($pdf_path);
}
My error log for /forms/test1 is probably the most useful - in particular the bit where there's the extra 'CakePdf' in the first line
2020-10-12 16:30:12 Error: [Cake\Error\FatalErrorException] Class 'CakePdf\Pdf\CakePdf\CakePdf' not found in /var/www/www.mysite.com/public_html/src/Controller/FormsController.php on line 343
Request URL: /forms/test1.pdf
Stack Trace:
#0 /var/www/www.mysite.com/public_html/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php(105): Cake\Error\BaseErrorHandler->handleFatalError(1, 'Class 'CakePdf\\...', '/var/www/www.my...', 343)
#1 [internal function]: Cake\Error\BaseErrorHandler->Cake\Error\{closure}()
#2 {main}
I’m struggling with a self-referencing belongsToMany association. To be clear I have a Models table and each model can have multiple accessories, which are also models. So I have a linking table, Accessories, with a model_id (the “parent” model) and an accessory_id (the “child” model).
I finally found how to declare this in the ModelsTable :
$this->belongsToMany('AccessoryModels', [
'className' => 'Models',
'through' => 'Accessories',
'foreignKey' => 'model_id',
'targetForeignKey' => 'accessory_id'
]);
$this->belongsToMany('ParentAccessoryModels', [
'className' => 'Models',
'through' => 'Accessories',
'foreignKey' => 'accessory_id',
'targetForeignKey' => 'model_id'
]);
I also got it working to retrieve these data in the Models view.
But I now have some issues for the addAccessory (and deleteAccessory) method in the Models controller and views.
Here is it in the controller :
public function addAccessory($id = null)
{
$model = $this->Models->get($id, [
'contain' => []
]);
if ($this->getRequest()->is(['patch', 'post', 'put'])) {
$accessory = $this->getRequest()->getData();
if ($this->Models->link($model, [$accessory])) {
return $this->redirect(['action' => 'view', $model->id]);
}
}
$models = $this->Models
->find('list', ['groupField' => 'brand', 'valueField' => 'reference'])
->order(['brand' => 'ASC', 'reference' => 'ASC']);
$this->set(compact('model', 'models'));
}
The view is only a select dropdown with the list of all available models (I'm using a plugin, AlaxosForm, but it takes the original CakePHP control() function behaviour) :
echo $this->AlaxosForm->label('accessory_id', __('Accessory'), ['class' => 'col-sm-2 control-label']);
echo $this->AlaxosForm->control('accessory_id', ['options' => $models, 'empty' => true, 'label' => false, 'class' => 'form-control']);
echo $this->AlaxosForm->button(___('Submit'), ['class' => 'btn btn-default']);
The problem is that the addAccessory() function won't work when getting the submitted data from the form. I see the problem, as when posting the inserted values, only an array with one accessory_id is given (for example ['accessory_id' => 1] and the link() doesn't know what to do with it. So I think it’s an issue about data formatting but don’t see how to get it correctly.
Saving links (like any other ORM saving methods) requires to pass entities, anything else will either be ignored, or trigger errors.
So you have to use the accessory_id to obtain an entity first, something like:
$accessoryId = $this->getRequest()->getData('accessory_id');
$accessory = $this->Models->AccessoryModels->get($accessoryId);
Furthermore you need to use the model/table that corresponds to the target entities (second argument) that you want to link (to the first argument), ie you'd have to use AccessoryModels, like:
$this->Models->AccessoryModels->link($model, [$accessory])
See also
Coobook > Database Access & ORM > Saving Data > Associate Many To Many Records
I am trying to get the data from another database in Drupal 7. But I am not able to get the data. Here is the code what I have tried.
I have added another database information in settings.php
$databases['default']['default'] = array(
'driver' => 'mysql',
'database' => 'drupal_testing',
'username' => 'root',
'password' => '',
'host' => 'localhost',
'prefix' => '',
);
$databases['sakshi']['default'] = array(
'driver' => 'mysql',
'database' => 'test',
'username' => 'root',
'password' => '',
'host' => 'localhost',
'prefix' => '',
);
And added the code in page.tpl.php for testing the connection.
<div class="col-lg-3 col-md-3 col-sm-12 col-xs-12 padtop30">
<h4> DB Connection test </h4>
<?php
try{
echo "inside try block";
db_set_active('sakshi');
$results = db_query("select name from test.user_names where phone = 432323");
$records = $results->fetchAll();
foreach ($records as $record) {
echo $record;
}
}catch(\PDOException $ex){
echo "inside catch block";
echo $ex;
}finally{
echo "finally block is executed";
db_set_active('default');
}
?>
</div>
Now when i am loading the data (refreshing the page) i am getting the error like
'PDOException' with message 'SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.semaphore' doesn't exist' in E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\database\database.inc:2227 Stack trace: #0 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\database\database.inc(2227): PDOStatement->execute(Array) #1 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\database\database.inc(697): DatabaseStatementBase->execute(Array, Array) #2 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\database\database.inc(2406): DatabaseConnection->query('SELECT expire, ...', Array, Array) #3 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\lock.inc(167): db_query('SELECT expire, ...', Array) #4 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\lock.inc(146): lock_may_be_available('rules_get_cache...') #5 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\sites\all\modules\rules\rules.module(368): lock_acquire('rules_get_cache...', 60) #6 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\sites\all\modules\rules\rules.module(1026): rules_get_cache('event_watchdog') #7 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\sites\all\modules\rules\modules\events.inc(180): rules_invoke_event('watchdog', Array) #8 [internal function]: rules_watchdog(Array) #9 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\module.inc(926): call_user_func_array('rules_watchdog', Array) #10 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\bootstrap.inc(1997): module_invoke('rules', 'watchdog', Array) #11 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\errors.inc(210): watchdog('php', '%type: !message...', Array, 3) #12 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\errors.inc(75): _drupal_log_error(Array, true) #13 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\bootstrap.inc(2576): _drupal_error_handler_real(4096, 'Object of class...', 'E:\\xampp5.6.20\\...', 321, Array) #14 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\sites\all\themes\my_theme\page.tpl.php(321): _drupal_error_handler(4096, 'Object of class...', 'E:\\xampp5.6.20\\...', 321, Array) #15 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\theme.inc(1526): include('E:\\xampp5.6.20\\...') #16 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\theme.inc(1208): theme_render_template('sites/all/theme...', Array) #17 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\common.inc(6045): theme('page', Array) #18 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\common.inc(5907): drupal_render(Array) #19 E:\xampp5.6.20\htdocs\drupal\drupal-7.53\includes\common.inc(2748): drupal_render_page('
I am new to Drupal. Can any one help me in this regard.
While according to the documentation, there is nothing wrong with the way you have set up your second connection, I have never been able to get it to work like that. The only way I have had it working is with the below, although I would agree there doesn't seem to be anything fundamentally different:
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupal_db',
'username' => 'root',
'password' => 'password',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
),
),
'second_database' =>
array (
'default' =>
array (
'driver' => 'mysql',
'database' => 'second_db',
'username' => 'root',
'password' => 'password',
'host' => 'localhost',
'port' => '',
'prefix' => '',
),
),
);
Then you should be able to do db_set_active('second_database').
The "Base table or view not found: 1146 Table 'test.semaphore' doesn't exist'" message is usually when Drupal has tried to do something Drupally while still attached to your second database, so don't forget to do db_set_active() to return the connection back to the Drupal database. There is no need to add 'default' as default is the assumed default database.
You should do this directly after fetching the data you need. So in your example, it should come after $records = $results->fetchAll();
Or, if you only need this connection in one place/ infrequently, you could set it up on the fly. More info here
Hope this helps
I have to use loggedIn user data in view therefore creating a variable AUTH_USER in AppController in beforeRender function.
82 public function beforeRender(Event $event)
83 {
84 if ($this->Auth->user('id')) {
85 $this->set('AUTH_USER', $this->Auth->user());
86 }
87 ...
88 ...
89 }
Whenever there is an error, instead of displaying actual error it shows following error without style formatting
Fatal error: Uncaught Error: Call to a member function user() on boolean in /path_to_app/src/Controller/AppController.php:84
Stack trace: #0 /path_to_app/src/Controller/ErrorController.php(54): App\Controller\AppController->beforeRender(Object(Cake\Event\Event))
#1 /path_to_app/vendor/cakephp/cakephp/src/Event/EventManager.php(422): App\Controller\ErrorController->beforeRender(Object(Cake\Event\Event))
#2 /path_to_app/vendor/cakephp/cakephp/src/Event/EventManager.php(391): Cake\Event\EventManager->_callListener(Array, Object(Cake\Event\Event))
#3 /path_to_app/vendor/cakephp/cakephp/src/Event/EventDispatcherTrait.php(78): Cake\Event\EventManager->dispatch(Object(Cake\Event\Event))
#4 /path_to_app/vendor/cakephp/cakephp/src/Controller/ in /path_to_app/src/Controller/AppController.php on line 84
Removing line 84 - 86 displays actual error
Edit 2
code for Auth component load in AppController initialize()
I have written the following code to load the AUTH component.
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'userModel' => 'Admins',
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Admins',
'action' => 'index'
],
'loginRedirect' => [
'controller' => 'Admins',
'action' => 'contentList'
],
'authError' => 'Did you really think you are allowed to see that?',
'logoutAction' => [
'controller' => 'Pages',
'action' => 'home'
]
]);
I had the same error and if you add this line to beforeRender() it should work:
$this->loadComponent('Auth');
It could be that you are not properly initializing the component in the initialize() function.
You haven't given a proper ID to the if statement to check. You have to send the logged in user's ID through the function's parameters and then check for that ID in the if statement.
Hi I'm currently working on a project and was wondering if it was possible to do two find functions in cakephp?
For example I am making a sports news website and I am grouping the news articles as top story, understory and headline.
What I want to do is retrive top stories so i can highlight these as the prominent story and then understory will be beneath as a lesser story and then headlines will be the least important.
This is what I have so far
function latestnews() {
$articles = $this->Article->find('all',
array('limit' =>3,
'order' =>
array('Article.date_created' => 'desc')));
if(isset($this->params['requested'])) {
return $articles;
}
$this->set('articles', $articles);
$articler = $this->Article->find('all',
array('Article.type' => 'topstory',
'Limit' => '1'
));
$this->set('articles', $articler);
}
however this doesn't seem to work, it doesn't limit the $articles function but instead echos all the data in the table.
in the view im doing a standard foreach statement to echo the data and I get thrown a undefined variable error.
Is what i am saying even possible or should I create different functions and then use them as elements?
Thanks for any input in advance!
You can bind the associationship with itself dynamically. Try this code:
function latestnews() {
$this->Article->bindModel(array('hasMany' => array('TopStory' => array('className' => 'Article',
'foreignKey' => false,
'conditions' => array('Article.type' => 'topstory')
),
'Highlight' .....
)));
$articles = $this->Article->find('all',
array('limit' =>3,
'order' => array('Article.date_created' => 'desc')));
if(isset($this->params['requested'])) {
return $articles;
}
$this->set('articles', $articles);
$articler = $this->Article->find('all',
array('Article.type' => 'topstory',
'Limit' => '1'
));
$this->set('articles', $articler);
}
Hope it will work for you.
#Arun Nope that didn't seem to work, I get this error, Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Article.type' in 'where clause' also I've tried to put it in an element with its own function and I then get thrown this error...
Notice (8): Undefined variable: data [APP/View/Elements/Articles/topstories.ctp, line 5]
Warning (2): Invalid argument supplied for foreach() [APP/View/Elements/Articles/topstories.ctp, line 5]
Notice (8): Undefined property: View::$Paginator [CORE/Cake/View/View.php, line 806]
Fatal error: Call to a member function prev() on a non-object in /Applications/XAMPP/xamppfiles/htdocs/kickoff/app/View/Elements/Articles/topstories.ctp on line 21
The controller code is the following...
function topstories() {
$this->paginate = array(
'conditions' => array('Article.type' => 'topstory'),
'limit' => 2,
'order' => array(
'date_created' => 'asc'
)
);
$data = $this->paginate('Article');
$this->set(compact('data'));
}
I find this error confusing as if I don't put this in an element and in a view instead it works perfectly! however in an element not so perfect :S
any ideas as to why this is the case??
Instead of using two find methods in one function I instead chose to simply create different functions and use them as elements for example...
function premiershiptopstory() {
$pltopnews = $this->Article->find('all', array(
'conditions' => array('Article.league' => 'premiership',
'Article.type' => 'topstory')));
if(!empty($this->request->params['requested'])) {
return $pltopnews;}
$this->set('article', $pltopnews);
}
However in the view you must request the action otherwise you will get thrown an error, to request the action simply use this line of code...
<?php $pltopnews = $this->requestAction('/Articles/premiershiptopstory');
Hope this helps others!