CakePHP 4 Saving Data Twice - cakephp

CakePHP is somehow saving the same data twice. For some reason I want to implement this add method such that $dummy is saved right away as someone goes directly to domain.com/recordings/add
It looks pretty straight forward and I've been scratching my head. I've checked for validation errors; I've tried disabling validation; I've tried using patchEntity() instead.
Though, one strange thing is that, if you go to domain.com/recordings/add by hitting the add recording button in domain.com/recordings/index (instead of typing the url out on the browser), the data is saved just once.
Controller:
public function add()
{
$dummy = [
"user_id" => 1,
"title" => "tgfbthgdthb",
"body" => "rgcvfghfhdxcgb",
"published" => 0,
];
$recording = $this->Recordings->newEntity($dummy);
$this->Recordings->save($recording);
}
Model/table:
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('recordings');
$this->setDisplayField('title');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER',
]);
$this->hasMany('Words', [
'foreignKey' => 'recording_id',
]);
}
Model/entity:
protected $_accessible = [
'user_id' => true,
'title' => true,
// 'slug' => true,
'body' => true,
'published' => true,
'created' => true,
'modified' => true,
'user' => true,
'words' => true,
];
The view:
<?php
/**
* #var \App\View\AppView $this
* #var \App\Model\Entity\Recording $recording
*/
?>
<div class="row">
<aside class="column">
<div class="side-nav">
<h4 class="heading"><?= __('Actions') ?></h4>
<?= $this->Html->link(__('List Recordings'), ['action' => 'index'], ['class' => 'side-nav-item']) ?>
</div>
</aside>
<div class="column-responsive column-80">
<div class="recordings form content">
<?= $this->Form->create($recording) ?>
<fieldset>
<legend><?= __('Add Recording') ?></legend>
<?php
echo $this->Form->control('user_id', ['options' => $users]);
echo $this->Form->control('title');
echo $this->Form->control('body');
echo $this->Form->control('published');
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>
</div>
</div>

Do not try to accommodate to people's lazyness, do not allow them to save data by simply visiting a URL, ie via a GET request, that's just going to cause trouble, and on top of that it's bad application design.
Implement at least a proper safeguard that only saves data for POST requests.
Browsers may issue multiple requests in various scenarios, from preflight OPTIONS requests to weird quirks, like for example Firefox aborting the request if doesn't find any encoding information in the first x bytes of response data, and then issuing a new request that assumes a specific encoding for the response.
public function add()
{
if ($this->request->is('post')) {
// save data here
}
}

Related

Cakephp 3.0 multiple files uploaded url

I am using 3.4 cakephp version but file uploaded successfully but i want the url to be updated in request entity. I can have one entity updated but not all like:
$post->url = WWW_ROOT.'uploads/filename';
Html form :
<?= $this->Form->create(null, ['class' => 'form-horizontal', 'id' => 'postSubmit', 'type' => 'file', 'autocomplete' => 'off'])?>
<div class="form-group">
<label for="inputEmail3" class="col-sm-4 control-label">Ad Category:</label>
<div class="col-sm-8">
<?= $this->Form->select('category_id', $categories, ['class' => 'form-control required categorySelected', 'empty' => 'Select Category'])?>
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-4 control-label">Photos(5 max):</label>
<div class="col-sm-8">
<?= $this->Form->input('images.', [ 'type' => 'file', 'id' => 'image', 'multiple' => 'multiple', 'accept' => 'image/jpg, image/jpeg', 'label' => false])?>
<p class="help-block">Good photos quick response</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-8 col-sm-offset-4">
<?= $this->Form->button('Post Now', ['class' => 'btn custom_btn btn-sm', 'type' => 'submit', 'label' => false])?>
</div>
</div>
</form>
Controller Action :
$post = $this->Posts->newEntity();
$post = $this->Posts->patchEntity($post, $this->request->getData());
if($this->request->getData()['images']) {
$dir = new Folder(WWW_ROOT.'uploads', true, 0755);
$files = $this->request->getData()['images'];
foreach ($files as $key => $file) {
if($file['error'] == 0) {
$info = pathinfo($file["name"]);
$newfilename = $info["filename"].'_'.time() . '.'. $info["extension"];
if(move_uploaded_file($file["tmp_name"], WWW_ROOT.'uploads/' . $newfilename)) {
$post->url = WWW_ROOT.'uploads/' . $newfilename;
}
}
}
}
if ($this->Posts->save($post)) {
$this->Flash->success('Post has been submitted successfully. Please wait
for approval');
}
I recommend you to implement the CakePHP3-Proffer described bellow:
Uploading multiple related images
This example will show you how to upload many images which are related to your current table class. An example setup might be that you have a Users table class and a UserImages table class. The example below is just baked code.
Tables
The relationships are setup as follows. Be sure to attach the behavior to the table class which is receiving the uploads.
// src/Model/Table/UsersTable.php
$this->hasMany('UserImages', ['foreignKey' => 'user_id'])
// src/Model/Table/UserImagesTable.php
$this->addBehavior('Proffer.Proffer', [
'image' => [
'dir' => 'image_dir',
'thumbnailSizes' => [
'square' => ['w' => 100, 'h' => 100],
'large' => ['w' => 250, 'h' => 250]
]
]
]);
$this->belongsTo('Users', ['foreignKey' => 'user_id', 'joinType' => 'INNER']);
Entities
Your entity must allow the associated field in it's $_accessible array. So in our example we need to check that the 'user_images' => true is included in our User entity.
Controller
No changes need to be made to standard controller code as Cake will automatically save any first level associated data by default. As our Users table is directly associated with our UserImages table, we don't need to change anything.
If you were working with a related models data, you would need to specify the associations to populate when merging the entity data using the 'associated' key.
Templates
You will need to include the related fields in your templates using the correct field names, so that your request data is formatted correctly.
// Don't forget that you need to include ['type' => 'file'] in your ->create() call
<fieldset>
<legend>User images</legend>
<?php
echo $this->Form->input('user_images.0.image', ['type' => 'file']);
echo $this->Form->input('user_images.1.image', ['type' => 'file']);
echo $this->Form->input('user_images.2.image', ['type' => 'file']);
?>
</fieldset>
How you deal with the display of existing images, deletion of existing images, and adding of new upload fields is up to you, and outside the scope of this example.

set value in controller to associated model befor save in cakephp

I have 'seller_businessestable andseller_business_categories` table. I am using a single form to save values to sellers and seller_businesses.
The form is like
<?= $this->Form->create() ?>
<?= $this->Form->input('company_name') ?>
<?= $this->Form->input('logo', ['type' => 'file']) ?>
<?= $this->Form->input('seller_business_categories.category_id') ?>
<?= $this->Form->button('Submit', ['type' => 'submit']) ?>
<?= $this->Form->end() ?>
The seller_business_categories has a column seller_id and I have to save the logged in user id in it.
I know to save value to table seller_businesses in controller like
$seller_business = $this->SellerBusinesses->newEntity();
$seller_business->seller_id = $this->Auth->user('id');
$this->SellerBusinesses->patchEntity($seller_business, $this->request->data, [
'associated' => ['SellerBusinessCategories']
]);
But how to save default value to associated model SellerBusinessCategories within controller ?
You need make relationship
SellerBusinessCategorie.php MODEL
public function initialize(array $config)
{
parent::initialize($config);
$this->table('seller_business_categories');
$this->hasMany('seller_businesses', [
'foreignKey' => 'seller_id'
]);
}
SellerBusinesses.php MODEL
public function initialize(array $config)
{
parent::initialize($config);
$this->belongsTo('seller_business_categories', [
'foreignKey' => 'category_id',
'joinType' => 'INNER'
]);
}
Controller
$seller_business = $this->SellerBusinesses->newEntity();
$seller_business->seller_id = $this->Auth->user('id');
$this->SellerBusinesses->patchEntity($seller_business, $this->request->data]);
NOW TRY..it works

How to add associated data while adding User simultaneously CakePHP 3.x?

I would like to be able to add a membership record at the same time I add a user. I can't seem to get it to work. I want to be able to select the membership level and have that data get sent to the controller where I can add the data, unless there is a way to just select the membership level and it will automatically create a membership record for the user that gets added.
The membership level contains the information for that level of membership and the membership record contains some information from the membership level and is associated to a user.
The add form I believe is where the problem lies, but just in case here are the important snippets of code. I tried to keep it as simple as possible.
Users Table Initialize Function:
public function initialize(array $config)
{
parent::initialize($config);
$this->table('users');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->hasOne('Memberships', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
}
Memberships Table Initialize Function:
public function initialize(array $config)
{
$this->table('memberships');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->hasOne('MembershipLevels', [
'foreignKey' => 'membership_level_id',
'joinType' => 'INNER'
]);
}
Users Controller Add Method:
public function add()
{
$user = $this->Users->newEntity($this->request->data(), [
'associated' => [
'Memberships' => ['associated' => ['MembershipLevels']]
]
]);
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->data(), [
'associated' => [
'Memberships' => ['associated' => ['MembershipLevels']]
]
]);
if ($$this->Users->save($user)) {
$this->Flash->success(__('You have been added.'));
} else {
$this->Flash->error(__('You could not be added. Please, try again.'));
}
}
$membershipLevels = $this->Users->Memberships->MembershipLevels->find('list', ['limit' => 200]);
$this->set(compact('user', 'membershipLevels'));
$this->set('_serialize', ['user', 'membershipLevels']);
}
Add Users Form:
<div class="form">
<h1>Join Now</h1>
<?= $this->Form->create($user); ?>
<fieldset>
<legend><?= __('User Info') ?></legend>
<?= $this->Form->input('full_name', ['required' => false]); ?>
<?= $this->Form->input('username', ['required' => false]); ?>
<?= $this->Form->input('email', ['required' => false]); ?>
<?= $this->Form->input('password', ['required' => false]); ?>
<?= $this->Form->input('password_confirmation', ['type' => 'password', 'required' => false]); ?>
<?php
if ($current_user['role'] === 1 && isset($logged_in)) {
echo $this->Form->input('role', ['type' => 'select', 'options' => ['1' => 'Admin', '2' => 'Editor', '3' => 'Author', '4' => 'Reader'], 'default' => '4']);
}
?>
</fieldset>
<fieldset>
<legend><?= __('Membership Info') ?></legend>
<?= $this->Form->label('Membership Level'); ?>
<?= $this->Form->input('memberships.membership_levels._id', ['options' => $membershipLevels, 'required' => false]); ?>
</fieldset>
<?= $this->Form->button(__('Sign Up'));?>
<?= $this->Form->end();?>
</div>
I changed the code a bit thanks to the comments and answers. The membership levels now show up in the form and I pick a membership level when saving the user, but the membership doesn't get saved as well, just the user. Any further suggestions?
How about start reading the migration guide, or doing the blog tutorial for CakePHP3? Your trial and error approach is time consuming and frustrating. I can't recommend this enough: Always read documentation before shooting in the darkness. There has a lot changed in CakePHP3. This includes the way the dot notation is used. Reading saving associations might help as well.
You don't use any longer the model prefix on the first level.
Model.field
is now just
field
For nested associations it's now
associated_data.field
associated_data.second_level_data.field
Notice that this is inflected and singular or plural depending on the kind of association.
I have updated my code to get the closest I can to getting all the automagic to work.
Key points:
1.) In controller I got the membership levels variable to pass to the view by adding this line. (notice the calling of the users table then memberships and then membershiplevels).
$membershipLevels = $this->Users->Memberships->MembershipLevels->find('list', ['limit' => 200]);
2.) In the view I added:
<?= $this->Form->input('memberships.membership_levels._id', ['options' => $membershipLevels, 'required' => false]); ?>
This is not a complete answer however because I still have to grab the membership level in the controller with a query and then manually save the data from that level to the memberships table.
I can at least populate the membership level input in the form dynamically and submit it.
I had looked over the bookmarker tutorial that I had previously done since it uses associations, but with that tutorial they are able to add the bookmarks_tags record automatically when you add a bookmark and I am not sure if it is due to the functions in the table files or not.

simple blog with croogo

I is not What is the problem, I made a simple blog in Croogo, the problem is it is not adding or modifying or delete, because Arabic language ??
function add in controller
`public function admin_add() {
$this->set('title_for_layout', __('Add Part'));
if (!empty($this->request->data)) {
$this->Part->create();
if ($this->Part->save($this->request->data)) {
$this->Session->setFlash(__('The Part has been saved'), 'default', array('class' => 'success'));
$this->redirect(array('action' => 'index'));//, $this->Part->id));
} else {
$this->Session->setFlash(__('The Part could not be saved. Please, try again.'), 'default', array('class' => 'error'));
}
}
}`
=>
model
`class Part extends AppModel {
public $name = 'Part';
var $belongsTo = array(
'Market' => array(
'className' => 'Market',
'foreignKey' => 'market_id',
)
);
protected $_displayFields = array(
'id',
'num_part',
'prix_part',
'prop_Pledge',
'prix_Pledge',
);
}
`
add view
<?php $this->extend('/Common/admin_edit'); ?>
<?php echo $this->Form->create('Part');?>
<fieldset>
<div class="tabs">
<ul>
<li><span><?php echo __('Part'); ?></span></li>
<?php echo $this->Layout->adminTabs(); ?>
</ul>
<div id="role-main">
<?php
echo $this->Form->label('num_part', 'العدد : ');
echo $this->Form->input('num_part',array('label' => false ));
echo $this->Form->label('prix_part', 'االمبلغ : ');
echo $this->Form->input('prix_part',array('label' => false ));
echo $this->Form->label('prop_Pledge', 'إقتراح التعهد : ');
echo $this->Form->input('prop_Pledge',array('label' => false ));
echo $this->Form->label('prix_Pledge', 'مبلغ التعهد : ');
echo $this->Form->input('prix_Pledge',array('label' => false ));
?>
</div>
<?php echo $this->Layout->adminTabs(); ?>
</div>
</fieldset>
<div class="buttons">
<?php
echo $this->Form->end(__('Save'));
echo $this->Html->link(__('Cancel'), array(
'action' => 'index',
), array(
'class' => 'cancel',
));
?>
</div>
message error : The requested address was not found on this server.
I don't think it is because of Arabic language because when you do :
echo $this->Form->label('prop_Pledge', 'إقتراح التعهد : ');
The second parameter is a text. I don't know which Cake version you're using but I think that the first field should be Part.prop_Pledge (Cake v3).
I suggest you to try to use debug() and exit to see where is the real problem or try to put remove arabic characters to see if this is the reason of you're problem.
Just a question where is your $this->Form->create() in view ?
line added to the database successfully but does not retoure to index
it displays an error message
Could you print the message error hello21 please ?
Hope this will help you.

Cakephp 1.3 select field options from list or enter new

I have a cakephp 1.3 app which get's a person's consent to participate in a study. I'm trying to link inclusion criteria and exclusion criteria for the study on the Add study page. The HABTM relationship is setup and working(If there's only one way to select them) What I'm trying to do now is display the current Inclusion Criteria as a list of checkboxes the person adding the study can select, but I also want a field where new criteria can be entered as a comma seperated list. Right now it will save the checkboxes, but I want it to also add the text entered in the field as well. Screen showing the Add study as it sits now is below. I don't really know how I would go about doing that. Is there a way to do this or will I have to take the data entered, sort through it and then add it to $this->data[inclusion field data]? An example would be nice. :) I've added the code I have so far below the image.
Controller:
/**
* Add a study.
*/
function add() {
if (!empty($this->data)) {
//get the inclusions from the text data
//Sort through the comma seperated list and add it to $this->data['Study']['Inclusions']???
$this->Study->create();
if ($this->Study->save($this->data)) {
$this->Session->setFlash(__('The study has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The study could not be saved. Please, try again.', true));
}
}
$this->set('inclusions', $this->Study->Inclusion->find('list', array(
'fields' => array('id', 'name'),
'order' => 'Inclusion.name',
'recursive' => 0,
)));
$this->set('exclusions', $this->Study->Exclusion->find('list', array(
'fields' => array('id', 'name'),
'order' => 'Exclusion.name',
'recursive' => 0,
)));
$this->set('forms', $this->Study->Form->find('list', array('order' => 'Form.name','recursive' => 0,)));
}
View:
<div class="studies form">
<?php echo $this->Form->create('Study', array('type' => 'file'));?>
<fieldset>
<legend><?php __('Add Study'); ?></legend>
<?php
echo $this->Form->input('studyname', array('label'=>'Study Name','required' => true));
echo $this->Form->input('studynumber', array('label'=>'Study Number','required' => true));
echo $this->Form->input('file', array('label'=>'Select Electronic Consent','type' => 'file'));
echo $this->Form->input('consent_form_date');
?>
<fieldset class="inclusion">
<legend><?php __('Inclusions'); ?></legend>
<div class="IncExc">
<?php
echo $this->Form->input('Inclusion',array(
'label' => false,
'type' => 'select',
'multiple' => 'checkbox',
'options' => $inclusions,
'selected' => $html->value('Inclusion.Inclusion'),
));
?>
</div>
<?php
echo $form->input('Inclusion.inclusions',array(
'type' => 'text',
'label' => __('Add New Inclusions',true),
'after' => __('Seperate each new Inclusion with a comma. Eg: family, sports, icecream',true)
));
?>
</fieldset>
<fieldset>
<legend><?php __('Exclusions'); ?></legend>
<div class="IncExc">
<?php
echo $this->Form->input('Exclusion',array(
'label' => false,
'type' => 'select',
'multiple' => 'checkbox',
'options' => $exclusions,
'selected' => $html->value('Exclusion.Exclusion'),
));
?>
</div>
</fieldset>
<fieldset style="width: 700px;">
<legend><?php //__('Forms'); ?></legend>
<?php /*
echo $this->Form->input('Form',array(
'label' => false,
'type' => 'select',
'multiple' => 'checkbox',
'options' => $forms,
'selected' => $html->value('Form.Form'),
));
*/ ?>
</fieldset>
</fieldset>
<?php echo $this->Form->end(__('Submit', true));?>
</div>
You are trying to do pretty much the same as he wanted to do: Saving tags into a database table in CakePHP
What you have to do is:
Check if the manual inclusion field is empty or not. If the field is empty ignore it and go to step 5
If the field is not empty, split it at comma or whatever sign you want to use as a seperator. You can now validate it if you want to.
Use all the inclusions of step 3 and save them in your custom or real inclusion table. You should keep track of those custom entries in some way, so you don't mess them up with those you provided. Save all the ids generated while saving within an array.
Merge the collected ids of step 3 with those you got from the form which were given by you.
Save all collected and given data to database
The answere in the post given above including the code there can be used to do that. You should get along with it pretty well if you read the whole post + code comments ;)
If you have any further questions, just ask ;)
Greetings
func0der

Resources