Cakephp3 : Invoked extension not recognized/configured: html - cakephp

I have a frustrating bug in Cakephp 3.7.1 . I know that a similar bug has been reported in
https://discourse.cakephp.org/t/invoked-extension-not-recognized-configured-html/5355 .
The bug is that the xml extension is working yet the html extention is not.
Here is my routes file.
<?php
use Cake\Routing\Router;
use Cake\Routing\Route\DashedRoute;
Router::defaultRouteClass(DashedRoute::class);
$routesArray = [
'/' => [
'defaults' => [
'controller' => 'Pages',
'action' => 'view',
'home',
],
'options' => [],
],
'/pages/*' => [
'defaults' => [
'controller' => 'Pages',
'action' => 'display',
],
'options' => [],
],
'/pages/:page' => [
'defaults' => [
'controller' => 'Pages',
'action' => 'view',
],
'options' => [
'pass' => [
'page',
],
],
],
];
$languages = ['sn', 'fr', 'en'];
foreach ($languages as $language) {
Router::prefix($language, function ($routes) use ($routesArray, $language) {
$routes->setExtensions([
'xml',
'html',
]);
foreach ($routesArray as $key => $value) {
if (!empty($value['options']['_name'])) {
$value['options']['_name'] .= $language;
}
$routes->connect(
$key,
$value['defaults'],
$value['options']
);
}
$routes->fallbacks(DashedRoute::class);
});
}
Router::scope('/', function ($routes) use ($routesArray) {
$routes->setExtensions([
'xml',
'html',
]);
foreach ($routesArray as $key => $value) {
$routes->connect(
$key,
$value['defaults'],
$value['options']
);
}
$routes->fallbacks(DashedRoute::class);
});

This is probably going to be fixed in 3.7.2, see https://github.com/cakephp/cakephp/pull/12845.
Until then, one workaround would be to unset the extension on the request handler component in the Controller.startup event, for example like this in your AppController class' beforeFilter() method:
public function beforeFilter(\Cake\Event\Event $event)
{
parent::beforeFilter($event);
$this->getEventManager()->on('Controller.startup', function () {
if ($this->RequestHandler->ext === 'html') {
$this->RequestHandler->ext = null;
}
});
// ...
}

Related

Belongs to Many: save custom field

I need help with saving/updating belongsToMany data with custom field.
I have a tables acl, managers, groups, sections.
I need to save/update data in acl table from sections/edit or sections/add
acl table
id|target_id|target_type|section_id
I need set target_id data 'user' or 'group' depending entities.
edit.ctp
echo $this->Form->control('managers._ids', ['class' => 'multiple', 'multiple' => true]);
echo $this->Form->control('groups._ids', ['class' => 'multiple', 'multiple' => true]);
SectionsTable.php
$this->belongsToMany('Managers', [
'joinTable' => 'acl',
'through' => 'Acl',
'foreignKey' => 'section_id',
'targetForeignKey' => 'target_id',
'conditions' => [
'target_type' => 'user'
]
]);
$this->belongsToMany('Groups', [
'joinTable' => 'acl',
'through' => 'Acl',
'foreignKey' => 'section_id',
'targetForeignKey' => 'target_id',
'conditions' => [
'target_type' => 'group'
]
]);
AclTable.php
$this->belongsTo('Managers', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'user'
]
]);
$this->belongsTo('Groups', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'group'
]
]);
I tried to use _joinData, but nothing work
before and after patchEntity()
foreach ($section->groups as &$group) {
$group->_joinData = ['target_type' => 'group'];
}
whithout save()
foreach ($this->request->data['managers']['_ids'] as $id) {
$manager = $this->Sections->Managers->get($id);
$manager->_joinData = new Entity(['target_type' => 'user'], ['markNew' => true]);
$this->Sections->Managers->link($section, [$manager]);
}
$this->request->data has a follow structure:
[
'controller' => '*',
'action' => '*',
'title' => '*',
'managers' => [
'_ids' => [
'0' => '*',
'1' => '*',
'2' => '*',
]
],
'groups' => [
'_ids' => [
'0' => '*',
'1' => '*',
'2' => '*',
]
]
]
Alltimes error: Cannot insert row, some of the primary key values are missing. Got (3, 114, ), expecting (target_id, section_id, target_type)
Now working with following code
$section = $this->Sections->patchEntity($section, $this->request->data, ['associated' => ['Managers', 'Groups']]);
foreach ($section->managers as &$manager) {
$manager->_joinData = new Entity([
'target_id' => $manager->id,
'target_type' => 'user',
'section_id' => $section->id
], ['markNew' => true]);
}
foreach ($section->groups as &$group) {
$group->_joinData = new Entity([
'target_id' => $group->id,
'target_type' => 'group',
'section_id' => $section->id
], ['markNew' => true]);
}
if ($this->Sections->save($section, ['associated' => ['Managers', 'Groups']])) {
$this->Flash->success(__('The section has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The section could not be saved. Please, try again.'));
But, maybe can do it don't listing all fields?
Also I need to create/add new records to acl table when adding new section
But section_id unavailable until save(). Can I save/add acl records by associations
Updated
AclTAble.php
$this->setPrimaryKey(['target_type', 'target_id', 'section_id']);
.
.
.
$this->belongsTo('Managers', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'user'
]
]);
$this->belongsTo('Groups', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'group'
]
]);
With primaryKey id, adding and editing entities working, but editing makes dublicates, it's are not perfect for me. And in documentations use composite primaryKey, so i use ['target_id', 'target_type', 'section_id'], with it cake don't make dublicated, but aggain show me error: Cannot insert row, some of the primary key values are missing. Got (8, 197, ), expecting (target_id, section_id, target_type)

CakePHP Auth->identify() returning false

I'm playing around with CakePHP and can't seem to get the login working. It seems that $this->Auth->identify() is constantly returning false and not allowing me to login.
I've read all previous posts regarding my issue, however, none have provided me with a solution. The users I am trying to log in as have all been created using the cake password hasher, which I have checked have been stored in the database. I have checked the password field length in the database, which is set to varchar (255), I've checked the Auth => authenticate => Form => fields are set to the correct values (the login.ctp fields are also correct). I also tried changing the $this->Form->control() to $this->Form->input() as someone suggested, with no luck.
AppController:
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Users',
'action' => 'classes'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'index'
]
]);
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
]
]);
login() function in UsersController:
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
pj($user);
if ($user) {
$this->Auth->setUser($user);
return $this->redirect(['controller' => 'users']);
}
$this->Flash->error(__('Invalid username or password, try again'));
}
}
login.ctp:
<div class="users form">
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Please enter your username and password') ?></legend>
<?= $this->Form->input('email') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>
EDIT: I forgot to add that I can successfully add users, I just can't log them in.
You are loading the AuthComponent twice in AppController. The second load with the config for form fields is not loaded.
Load the component one time with the wanted config.
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginRedirect' => [
'controller' => 'Users',
'action' => 'classes'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'index'
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
]
]);

cakephp: plumSearch - Changing filter's label in parameters

Using PlumSearch plugin, it is mentioned in its documentation that we can modify 'label':
formConfig: Contains Form::input $options settings like class, input type, label name...
In my controller/initialize(), I need to change the label of some fields ("IP Address" instead of "Ip Adress", "Status" instead of "Asset Status"):
public function initialize()
{
parent::initialize();
$parameters = [
['name' => 'serial_number', 'className' => 'Input'],
['name' => 'model_number', 'className' => 'Input'],
['name' => 'ip_address', 'label' => 'IP Address', 'className' => 'Input'],
];
if ($this->request->param('action') == 'reportFacility') {
$statuses = $this->AssetsAssignations->AssetStatuses->find('list')->order(['name' => 'asc']);
$this->set(compact('asset_statuses'));
$parameters = [
['name' => 'asset_status_id', 'className' => 'Select', 'label' => 'Status',
'finder' => $statuses
],
];
} elseif ($this->request->param('action') == 'reportClient') {
$clients = $this->AssetsAssignations->Clients->find('list')->order(['last_name' => 'asc', 'first_name' => 'asc']);
$this->set(compact('clients'));
$parameters = [
['name' => 'client_id', 'className' => 'Select', 'label' => 'Client',
'finder' => $clients
],
];
} elseif ($this->request->param('action') == 'reportRoom') {
$rooms = $this->AssetsAssignations->Rooms->find('list')->order(['name' => 'asc']);
$this->set(compact('rooms'));
$parameters = [
['name' => 'room_id', 'className' => 'Select', 'label' => 'Room',
'finder' => $rooms
],
];
}
$this->loadComponent('PlumSearch.Filter', ['parameters' => $parameters]);
}`
The code above did not work for labels.
I was told to use the following code:
$inputOptions = [
'search' => [
'placeholder' => __('Type to search...'),
'class' => 'form-control',
'label' => 'Search'
]
];
$this->set(compact('inputOptions'));
but I failed to determine where and how in my code.
Any help please ?
simply you have to add it to the $parameters array this way
$parameters = [
/* other fields here */
[
'name' => 'ip_address',
'className' => 'Input',
'formConfig' => ['label' => 'IP Address']
],
];

multiple select for hasMany association in CakePHP 3

I have two tables seller_businesses and seller_business_categories. and their association is as follows
SellerBusinessesTable.php
$this->hasMany('SellerBusinessCategories', [
'foreignKey' => 'seller_business_id'
]);
SellerBusinessCategories.php
$this->belongsTo('SellerBusinesses', [
'foreignKey' => 'seller_business_id',
'joinType' => 'INNER'
]);
I'm using a single form to save data in both tables
<?= $this->Form->create($sellerBusiness, ['type' => 'file']) ?>
<?= $this->Form->input('company_name') ?>
<?= $this->Form->input('proof', ['type' => 'file']) ?>
<?= $this->Form->input('seller_business_categories._category_ids', ['multiple' => true, 'options' => $categories]) ?>
<?= $this->Form->button('submit', ['type' => 'submit']) ?>
<?= $this->Form->end() ?>
And controller action is
$sellerBusiness = $this->SellerBusinesses->newEntity();
if ($this->request->is('post')) {
$sellerBusiness->seller_id = $this->Auth->user('id');
$sellerBusiness = $this->SellerBusinesses->patchEntity($sellerBusiness, $this->request->data, [
'associated' => [
'SellerBusinessCategories'
]
]);
debug($sellerBusiness);
if ($save_s_b = $this->SellerBusinesses->save($sellerBusiness)) {
debug($save_s_b);
$this->Flash->success(__('The seller business has been saved.'));
return $this->redirect(['controller' => 'SellerBusinesses', 'action' => 'view', $save_s_b->id]);
} else {
$this->Flash->error(__('The seller business could not be saved. Please, try again.'));
}
}
But this is not saving record to seller_business_categories table.
From document Here
// Multiple select element for belongsToMany
echo $this->Form->input('tags._ids', [
'type' => 'select',
'multiple' => true,
'options' => $tagList,
]);
But this is not working. Is there any other way for hasMany
debug($this->request->data); gives
'seller_business_categories' => [
'_category_ids' => [
(int) 0 => '1',
(int) 1 => '2'
]
],
and debug($sellerBusiness); after patchEntity
object(App\Model\Entity\SellerBusiness) {
'seller_id' => (int) 16,
'company_name' => 'My company',
'seller_business_categories' => [
(int) 0 => object(App\Model\Entity\SellerBusinessCategory) {
(int) 0 => '1',
(int) 1 => '2',
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
(int) 0 => true,
(int) 1 => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'SellerBusinessCategories'
}
],
'[new]' => true,
'[accessible]' => [
'*' => true,
],
'[dirty]' => [
'seller_id' => true,
'company_name' => true,
'seller_business_categories' => true,
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'SellerBusinesses'
}
and error
Error: SQLSTATE[HY000]:
General error: 1364 Field 'category_id' doesn't have a default value in seller_business_categories table
SellerBusinessesTable
$this->belongsToMany('Categories');
CategoriesTable
$this->belongsToMany('SellerBusinesses', [
'foreignKey' => 'category_id',
'targetForeignKey' => 'seller_business_id',
'joinTable' => 'categories_seller_businesses'
]);
// Pivot tables must be sorted alphabetically
bin/cake bake migration CreateCategoriesSellerBusinesses seller_business_id:integer category_id:integer created modified
CategoriesSellerBusinessesTable
$this->belongsTo('SellerBusinesses', [
'foreignKey' => 'seller_business_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Categories', [
'foreignKey' => 'category_id',
'joinType' => 'INNER'
]);
Add.ctp
<?= $this->Form->create($sellerBusiness, ['type' => 'file']) ?>
...
<?= $this->Form->input('categories', ['type' => 'select', 'options' => $categories, 'multiple' => 'select', 'label' => __('Categories')]) ?>
...
<?= $this->Form->end() ?>
SellerBusinessesController
public function add()
{
$sellerBusiness = $this->SellerBusinesses->newEntity();
if ($this->request->is('post')) {
$sellerBusiness = $this->SellerBusinesses->patchEntity($sellerBusiness, $this->request->data);
$sellerBusiness->seller_id = $this->Auth->user('id');
if(isset($this->request->data['categories']))
{
$sellerBusiness -> categories = $this->SellerBusinesses->Categories->find()->where(['id IN' => $this->request->data['categories']])->all()->toArray();
}
if ($this->SellerBusinesses->save($sellerBusiness)) {
$this->Flash->success(__('The sellerBusiness has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The seller could not be saved. Please, try again.'));
}
}
$categories = $this -> SellerBusinesses-> Categories-> find('treeList');
$this->set(compact('sellerBusiness', 'categories'));
$this->set('_serialize', ['sellerBusiness']);

CakePHP 3.0 Can't save hasMany associated data

I've problem when saving data with hasMany association
This is my table
1) post table: each item has an unique id.
id | title | ...
1 | Aloha | ...
2) images table
id | post_id | image | ...
1 | 1 | abc.jpg | ...
2 | 1 | efg.jpg | ...
My Model (Table)
Posts Model
// PostsTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class PostsTable extends Table {
public function initialize(array $config) {
$this->table('posts');
$this->displayField('title');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->hasMany('Images', [
'foreignKey' => 'id'
]);
}
}
...
Images Model
// ImagesTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class ImagesTable extends Table {
public function initialize(array $config) {
$this->table('images');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Posts');
}
}
...
My Controller
// PostsController.php
...
public function add() {
$post = $this->Posts->newEntity($this->request->data, [
'associated' => ['Images']
]);
if ($this->request->is('post')) {
if ($this->Posts->save($post, ['associated' => ['Images']])) {
$this->Flash->success('The post has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The post could not be saved. Please, try again.');
}
}
$this->set('post', $post);
}
...
My Template
// add.ctp
<?= $this->Form->create($post); ?>
<?php echo $this->Form->input('title'); ?>
<?php echo $this->Form->input('images.0.image'); ?>
<?php echo $this->Form->input('images.1.image'); ?>
<?php echo $this->Form->input('images.2.image'); ?>
<?= $this->Form->button(__('Submit'), ['class' => 'button-green']) ?>
<?= $this->Form->end() ?>
Input array result Debug
[
'title' => 'Hello',
'images' => [
(int) 0 => [
'image' => 'testa.jpeg'
],
(int) 1 => [
'image' => 'testb.jpeg'
],
(int) 2 => [
'image' => 'testc.jpeg'
]
]
]
(Update)
debug($post)
object(App\Model\Entity\Story) {
'new' => true,
'accessible' => [
'title' => true,
'images' => true
],
'properties' => [
'title' => 'Hello',
'images' => [
(int) 0 => object(App\Model\Entity\Image) {
'new' => true,
'accessible' => [
'post_id' => true,
'image' => true,
'post' => true
],
'properties' => [
'image' => 'testa.jpeg'
],
'dirty' => [
'image' => true
],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'Images'
},
(int) 1 => object(App\Model\Entity\Image) {
'new' => true,
'accessible' => [
'post_id' => true,
'image' => true,
'post' => true
],
'properties' => [
'image' => 'testb.jpeg'
],
'dirty' => [
'image' => true
],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'Images'
},
(int) 2 => object(App\Model\Entity\Image) {
'new' => true,
'accessible' => [
'post_id' => true,
'image' => true,
'post' => true
],
'properties' => [
'image' => 'testc.jpeg'
],
'dirty' => [
'image' => true
],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'Images'
}
]
],
'dirty' => [
'title' => true,
'images' => true
],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'Stories'
}
I can't figure out what I am doing wrong
Thanks
I haven't looked everything, but I saw there is an error in your association declaration:
$this->hasMany('Images', [
'foreignKey' => 'id'
]);
The docs say:
foreignKey: the name of the foreign key found in the other model. This is especially handy if you need to define multiple hasMany relationships. The default value for this key is the underscored, singular name of the actual model, suffixed with ‘_id’.
So it should be:
$this->hasMany('Images', [
'foreignKey' => 'post_id'
]);
or even:
$this->hasMany('Images');
I've just finished my 3-hour tour with saving hasMany content along with the main model. This struggle seems to be even worse, if considered saving many main model's objects with many associated items.
Foreign key in hasMany relationship is the singular name of the current model (entity) with _id suffix, so it's like:
class MainModel extends Table {
...
public function initialize(array $config) {
...
// remember the "s" at the end of the name
$this->hasMany('VeryWeirdCalleds', [
'className' => 'VeryWeirdCalleds',
'foreignKey' => 'main_model_id',
'propertyName' => 'very_weird_calleds'
]);
...
}
...
}
Then, you set the accessible in the MAIN Entity, so that the MAIN model can save the association based on "very_weird_calleds" index:
class MainModel extends Entity {
protected $_accessible = [
...
'very_weird_calleds' => true,
];
}
And the last (but not least): the Controller save. It's usually the hardest part to overcome, due to the fact, that docs do not clarify the whole process in detail:
class MainModelsController extends AppController {
public function add($data) {
$data = [
[
'name' => 'Hello',
'body' => 'Bla bla',
'very_weird_calleds' => [
[
'name' => 'Very Weird Called'
]
]
]
];
foreach ($data as $record) {
$main = $this->MainModels->newEntity($record);
if(isset($record['images']) && !empty($record['images'])) {
foreach($record['images'] as $record_image) {
$image = $this->MainModels->VeryWeirdCalleds->newEntity();
$image->IMAGE = $record_image['IMAGE'];
$import->very_weird_calleds[] = $image;
}
}
if (!$this->MainModels->save($main)) {
$this->Flash->error('The main model could not be saved. Please, try again.');
}
}
}
Explanation? First of all, we loop through the data, previously prepared as follows:
[ 'main', 'model', 'data', 'association_accessible_property' => [ 'associated_data' ] ] ]
Then we create new entries for associated data, using the same method as for the main model. The last thing, is to add those associated Entities to the main model Entity.
Pay an extreme attention to the names given in this example. The 's'-es and CamelCases are not coincidental.
try this :
<?php echo $this->Form->input('0.Images.image'); ?>
<?php echo $this->Form->input('1.images.image'); ?>
<?php echo $this->Form->input('2.images.image'); ?>
with int before , according with http://book.cakephp.org/3.0/en/views/helpers/form.html#field-naming-conventions

Resources