I'm working on this project and at first it has a single file upload that works perfectly fine, but had to change to multiple file upload and now I just can't make it work!
Getting an "Headers aready sent" error:
Deprecated (16384): Accessing `here` as a property will be removed in 4.0.0. Use request->getAttribute("here") instead. - /home1/thecyb80/seibo.the-cyberpunk.com/src/Controller/AppController.php, line: 92
You can disable deprecation warnings by setting `Error.errorLevel` to `E_ALL & ~E_USER_DEPRECATED` in your config/app.php. [CORE/src/Core/functions.php, line 311]
Warning (512): Unable to emit headers. Headers sent in file=/home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php line=856 [CORE/src/Http/ResponseEmitter.php, line 51]
Warning (2): Cannot modify header information - headers already sent by (output started at /home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php:856) [CORE/src/Http/ResponseEmitter.php, line 152]
Warning (2): Cannot modify header information - headers already sent by (output started at /home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php:856) [CORE/src/Http/ResponseEmitter.php, line 185]
Warning (2): Cannot modify header information - headers already sent by (output started at /home1/thecyb80/seibo.the-cyberpunk.com/vendor/cakephp/cakephp/src/Error/Debugger.php:856) [CORE/src/Http/ResponseEmitter.php, line 185]
Here's my code: add.ctp
<?= $this->Form->create($atividade, ['type' => 'file']) ?>
[...]
<div class="form-group m-0">
<label class="btn btn-light p-3 rounded border d-flex align-items-center justify-content-center flex-column" style="cursor: pointer; min-height: 350px;">
<strong class="d-block">Selecione o(s) arquivo(s) da atividade. Você pode enviar até 10 arquivos.</strong>
<span class="exercicio-nome d-flex aling-items-center justify-content-center w-100 mt-3"></span>
<?= $this->Form->file('arquivos[]', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
</label>
</div>
Validation founded in AtividadesTable.php (that's the only occurrence of the field):
$validator
->scalar('arquivos')
->maxLength('arquivos', 255)
->allowEmptyString('arquivos')
->allowEmptyFile('arquivos');
I've tried several solutions, that I've found over the internet, but none helped me. I'm using CakePHP 3.8.11 over PHP 7.2.31.
Here'se my composer.json modules installed (don't know if it can help):
"require": {
"php": ">=5.6",
"cakephp/cakephp": "3.8.*",
"cakephp/migrations": "^2.0.0",
"cakephp/plugin-installer": "^1.0",
"mobiledetect/mobiledetectlib": "2.*"
}
Since I can't go over this step, I'm assuming that for now, my Controller is irrelevant. What can I do?
Edit: 06/04 (asked by Salines)
Multiple file upload (uploaded 4 files)
Using
<?= $this->Form->file('arquivos[]', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
(Page just refreshs)
Single file upload
Using
<?= $this->Form->file('arquivos[]', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
(Page just refreshs)
Multiple file upload (uploaded 4 files)
Using
<?= $this->Form->file('arquivos', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
/src/Controller/AtividadesController.php (line 159)
[
'nome' => 'Atividade teste',
'status' => '1',
'users' => [
'_ids' => [
(int) 0 => '306'
]
],
'turmas' => [
'_ids' => [
(int) 0 => '17'
]
],
'materias' => [
'_ids' => [
(int) 0 => '45'
]
],
'descricao' => '<p>Teste</p>
',
'comeca_dia' => [
'year' => '2020',
'month' => '06',
'day' => '04'
],
'termina_dia' => [
'year' => '2020',
'month' => '06',
'day' => '04'
],
'video' => '',
'aviso_do_professor' => 'Teste',
'arquivos' => [
'tmp_name' => '/tmp/phpafKkWr',
'error' => (int) 0,
'name' => 'imagem_sobre.png',
'type' => 'image/png',
'size' => (int) 600995
]
]
Multiple file upload (uploaded 4 files)
Using
<?= $this->Form->file('arquivos. ', [ 'class' => 'exercicio-item', 'multiple' => 'multiple', 'style' => 'display: none;', 'label' => [ 'class' => 'd-none' ] ]) ?>
Output
(Page just refreshs)
AtividadesController
I'll show my AtividadesController.php (add method):
/**
* Add method
*
* #return \Cake\Http\Response|null Redirects on successful add, renders view otherwise.
*/
public function add($nivelId = null)
{
$atividade = $this->Atividades->newEntity();
if ($this->request->is('post')) {
// Edit - StackOverflow
debug($this->getRequest()->getData()); exit;
$atividade = $this->Atividades->patchEntity($atividade, $this->request->getData());
die(debug($_FILES));
// Salvando os arquivos
if (!empty($_FILES['arquivos']['name'])) {
$file = $_FILES['arquivos'];
$arquivoName = $file['name'];
$userId = $this->Auth->user('id');
$ext = substr(strtolower(strrchr($arquivoName, '.')), 1);
$arr_ext = array('zip', 'rar', 'pdf', 'doc', 'docx', 'ppt', 'pptx');
if (in_array($ext, $arr_ext)) {
$imgHashed = md5($arquivoName) . time() . '.' . $ext;
$fileDir = WWW_ROOT . 'files/' . $userId;
if (!is_dir($fileDir)) {
mkdir($fileDir);
}
#move_uploaded_file($file['tmp_name'], $fileDir . '/' . $imgHashed);
$atividade['arquivos'] = $imgHashed;
$atividade['arquivo_nome'] = $arquivoName;
} else {
$this->Flash->error(__("Só aceitamos imagens dos tipos 'zip', 'rar', 'pdf', 'doc', 'docx', 'ppt' ou 'pptx'."));
return $this->redirect(['action' => 'add']);
}
}
if ($this->Atividades->save($atividade)) {
$this->Flash->success(__('A atividade foi salva.'));
return $this->redirect(['action' => 'index', $this->Auth->user('id')]);
}
$this->Flash->error(__('A atividade não pode ser salva. Por favor, tente novamente.'));
}
$arquivos = $this->Atividades->Arquivos->find('list');
$materias = $this->Atividades->Materias->find('list');
if ($nivelId) {
$turmas = $this->Atividades->Turmas->find('list')->matching('Nivels', function($q) use ($nivelId) {
return $q
->select()
->where(['Nivels.id' => $nivelId]);
});
} else {
$turmas = $this->Atividades->Turmas->find('list');
}
$users = $this->Atividades->Users->find('list')->where(['tipo' => 'professor']);
$this->set(compact('atividade', 'arquivos', 'materias', 'turmas', 'users'));
}
Am I missing something? Some CakePHP component, maybe? Some PHP extension?
Related
I need to create the upload process where the user can upload multiple files at once, using the file field with html5 multiple attr. Name of the file must be saved in the associated model.
I can run successfully upload one file and save the file name in the photos table, across the field:
echo $this->Form->file('photos.name');
But if I want to enable upload more photos with
echo $this->Form->input('title'); // post title
echo $this->Form->input('maintext'); // post main text,
... etc
echo $this->Form->file('photos[].name',['multiple'=>true]);
I get into the problem, and try to understand where I make mistakes, but without success.
PostsController:
public function add()
{
$post = $this->Posts->newEntity();
if ($this->request->is('post')) {
$post = $this->Posts->patchEntity($post, $this->request->data);
if ($this->Posts->save($post)) {
$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(compact('post'));
$this->set('_serialize', ['post']);
}
PostsTable:
$this->addBehavior('Upload');
$this->hasMany('Photos', [
'foreignKey' => 'post_id'
]);
UploadBehavior
All standard callbacks where I currently perform debug $data / $entity, but only in beforeMarshal i use:
$data = Hash::get($data,'name');
debug($data);
// debug output
[
'name' => 'HPIM3869.JPG',
'type' => 'image/jpeg',
'tmp_name' => 'C:\xampp\tmp\phpF02D.tmp',
'error' => (int) 0,
'size' => (int) 1295448
],
...
In beforeSave and afterSave
My form is OK, the data properly come in before Marshal method, if I upload 3 files, I also see the same number of debug outputs, but in beforSave and afterSave debug only show the first file like this:
debug($entity);
object(App\Model\Entity\Photos) {
'name' => [
'name' => 'HPIM3435.JPG',
'type' => 'image/jpeg',
'tmp_name' => 'C:\xampp\tmp\php5839.tmp',
'error' => (int) 0,
'size' => (int) 1517410
],
'post_id' => (int) 469,
'created' => object(Cake\I18n\Time) {
'time' => '2015-10-07T09:22:44+0200',
'timezone' => 'Europe/Berlin',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-10-07T09:22:44+0200',
'timezone' => 'Europe/Berlin',
'fixedNowTime' => false
},
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'name' => true,
'post_id' => true,
'created' => true,
'modified' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Photos'
}
Edit:
In the purpose of the test, I create such a form:
echo $this->Form->input('name',['value'=>'zzz']);
echo $this->Form->input('photos.0.name',['value'=>'zzz']);
echo $this->Form->input('photos.1.name',['value'=>'hhh']);
echo $this->Form->input('photos.2.name',['value'=>'fff']);
Also it only be saved the first result.
I need help to understand how to save multiple form data. Where I go wrong?
I think your field should be like this
echo $this->Form->file('photos.name.',['multiple'=>true]); //note dot notation at end of name. It will generate input name as array
I'm having the hardest time with saving multiple records. I've tried a million things, but I end up with the same problem: my records are not saved and I can't see any errors. Bear in mind that I'm new to cakephp and a novice coder.
Am I missing something obvious and crucial?
Table:
$this->table('splits');
$this->displayField('id');
$this->primaryKey('id');
$this->belongsTo('Transactions', [
'foreignKey' => 'transaction_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Accounts', [
'foreignKey' => 'account_credit_id',
'joinType' => 'INNER'
]);
Controller:
$splits = $this->Splits->newEntity();
if ($this->request->is('post')) {
$splits = $this->Splits->newEntities($this->request->data());
debug($splits);
foreach ($splits as $split){
$this->Splits->save($split);
}
}
$transactions = $this->Splits->Transactions->find('list', ['limit' => 200]);
$accounts = $this->Splits->Accounts->find('list', ['limit' => 200]);
$this->set(compact('split', 'transactions', 'accounts'));
$this->set('_serialize', ['split']);
Template:
echo $this->Form->input('Splits.1.transaction_id', ['options' => $transactions]);
echo $this->Form->input('Splits.1.amount', ['type' => 'float']);
echo $this->Form->input('Splits.1.account_id', ['options' => $accounts]);
echo $this->Form->input('Splits.2.transaction_id', ['options' => $transactions]);
echo $this->Form->input('Splits.2.amount', ['type' => 'float']);
echo $this->Form->input('Splits.2.account_id', ['options' => $accounts]);
echo $this->Form->input('Splits.3.transaction_id', ['options' => $transactions]);
echo $this->Form->input('Splits.3.amount', ['type' => 'float']);
echo $this->Form->input('Splits.3.account_id', ['options' => $accounts]);
Debug on $splits:
[
(int) 0 => object(App\Model\Entity\Split) {
(int) 1 => [
'transaction_id' => '108',
'amount' => '100.33',
'account_id' => '2'
],
(int) 2 => [
'transaction_id' => '108',
'amount' => '50.22',
'account_id' => '4'
],
(int) 3 => [
'transaction_id' => '108',
'amount' => '65.22',
'account_id' => '5'
],
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
(int) 1 => true,
(int) 2 => true,
(int) 3 => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Splits'
}
]
Did you somewhere saw this Table.index.field style being used, or did you just tried something and hoped it would work?
When saving many records respectively creating many entities, the expected format is a numerically indexed array that holds the data for the individual records, just as shown in the docs
Cookbook > Database Access & ORM > Saving Data > Converting Multiple Records
When creating forms that create/update multiple records at once you
can use newEntities():
[...]
In this situation, the request data for multiple articles should look
like:
$data = [
[
'title' => 'First post',
'published' => 1
],
[
'title' => 'Second post',
'published' => 1
],
];
So your inputs should not use the table name, but just the index and the field name, like
echo $this->Form->input('0.transaction_id', /* ... */);
echo $this->Form->input('0.amount', /* ... */);
echo $this->Form->input('0.account_id', /* ... */);
echo $this->Form->input('1.transaction_id', /* ... */);
echo $this->Form->input('1.amount', /* ... */);
echo $this->Form->input('1.account_id', /* ... */);
echo $this->Form->input('2.transaction_id', /* ... */);
echo $this->Form->input('2.amount', /* ... */);
echo $this->Form->input('3.account_id', /* ... */);
Try this:
$splits = TableRegistry::get('splits');
$entities = $splits->newEntities($this->request->data());
foreach ($entities as $entity) {
$splits->save($entity);
}
Try this example to insert multiple recored in cakphp 3.x
$passwords = $this->request->data('password_id');
foreach ($passwords as $password) {
$data = [
'event_id' => $this->request->data('event_id'),
'password_id' => $password
];
$eventPasswordAll = $this->EventPasswordAll->newEntity();
$this->EventPasswordAll->patchEntity($eventPasswordAll, $data);
$this->EventPasswordAll->save($eventPasswordAll );}
I hope it is useful to your question
please reviwe it, Thanks !
If you’d like to process all the entities as a single transaction you can use transactional():
Although using a loop, "transations" avoids errors if the "save" does not work.
// In a controller.
$articles->getConnection()->transactional(function () use ($articles, $entities) {
foreach ($entities as $entity) {
$articles->save($entity, ['atomic' => false]);
}
});
Converting Multiple Records - CakePHP 3
I try to validate file, befor upload, but I doing something wrong.
This is my file in form type:
->add('file', 'file', array(
'constraints' => [
new File([
'maxSize' => '5M',
'mimeTypes' => [
'image/*'
],
'mimeTypesMessage' => 'Only images allowed!'
])
],
'multiple' => 'multiple',
'data_class' => null,
'required' => false,
'mapped' => false,
'attr' => array(
'maxSize' => '1024k',
'accept' => 'image/*',
)
))
If I select .txt, .php, ... to upload, so it's normally uploaded, without errors.
How to make it work?
Thanks
EDIT:
My Upload Function:
private function uploadImg($files)
{
$path = array();
foreach ($files as $file) {
$extension = $file->guessExtension();
if (!$extension) {
$extension = 'bin';
}
$randomName = 'image' . date('Y-m-d-H-i-s') . uniqid() . '.' . $extension;
$file->move('uploads/images/', $randomName);
$path[] = $randomName;
}
return $path;
}
and in controller:
$ads->setPath(implode(',', $this->uploadImg($form['file']->getData())));
I have a cakedc search plugin with cakephp 3.0 working fine, but would like to have more advanced search filters like:
city = 'Los Angeles';
city != 'Los Angeles';
city LIKE '%Angeles%';
city LIKE 'Los%';
city NOT LIKE '%Angeles%';
city NOT LIKE 'Los%';
etc...
So i'm looking to add 2 dropdown select and 1 text input to achieve this.
'city' would be in a dropdown of db fields.
=, !=, like %?%, like %?, not like ?% conditions would be a dropdown
'los angeles' search value would be typed in.
Figured out, might not be perfect but seems to work fine:
View:
<?php echo $this->Form->input('dbfield', ['label' => 'Field', 'options' => ['' => '', 'region' => 'Region', 'city' => 'City', 'keyword' => 'Keyword']]); ?>
<?php echo $this->Form->input('dbconditions', [
'label' => 'Condition',
'options' => [
'' => '',
'contains' => 'contains',
'doesnotcontain' => 'does not contain',
'beginswith' => 'begins with',
'endswith' => 'ends with',
'isequalto' => 'is equal to',
'isnotequalto' => 'is not equal to',
],
]); ?>
<?php echo $this->Form->input('dbvalue', ['label' => 'Value', 'class' => 'form-control input-sm']); ?>
Model
public $filterArgs = [
'dbfield' => [
'type' => 'finder',
'finder' => 'conds0',
],
'dbconditions' => [
'type' => 'finder',
'finder' => 'conds0',
],
'dbvalue' => [
'type' => 'finder',
'finder' => 'conds',
],
];
public function findConds0(Query $query, $options = []) {
}
public function findConds(Query $query, $options = []) {
if($options['data']['dbconditions'] == 'contains') {
$conditions = [
$options['data']['dbfield'] . ' LIKE' => '%' . $options['data']['dbvalue'] . '%',
];
}
if($options['data']['dbconditions'] == 'doesnotcontain') {
$conditions = [
$options['data']['dbfield'] . ' NOT LIKE' => '%' . $options['data']['dbvalue'] . '%',
];
}
if($options['data']['dbconditions'] == 'beginswith') {
$conditions = [
$options['data']['dbfield'] . ' LIKE' => $options['data']['dbvalue'] . '%',
];
}
if($options['data']['dbconditions'] == 'endswith') {
$conditions = [
$options['data']['dbfield'] . ' LIKE' => '%' . $options['data']['dbvalue'],
];
}
if($options['data']['dbconditions'] == 'isequalto') {
$conditions = [
$options['data']['dbfield'] => $options['data']['dbvalue'],
];
}
if($options['data']['dbconditions'] == 'isnotequalto') {
$conditions = [
$options['data']['dbfield'] . ' != ' => $options['data']['dbvalue'],
];
}
return $query->where($conditions);
}
I clean the code, only beacuse look a big code.
In other way, why you include an empty option in the Condition select input? not look better with a default search condition?
Saludos
i wish select an element of dropdownlist (choose a Project) and with JSHELPER (ajax) update the GRAPH that show statistics of this Project.
I can choose the Project and through the 'POST' I can generate the array graph, but i cannot show the GRAPH. I tested without JSHELPER and show my Graph.
MY VIEW CODE:
<b>ESCOLHA O PROJETO: </b>
<?php
echo $this->Form->select('projects', array($projects), array('multiple' => false,
'class' => 'span2',
'id' => 'projectsTest'));
?>
</br>
<div id="chart_div" >
</div>
<?php
$this->Js->get('#projectsTest')->event('change', $this->Js->request(array(
'controller' => 'Registos',
'action' => 'timePerProjectIssueTypeChart'
), array(
'update' => '#chart_div',
'async' => true,
'method' => 'post',
'dataExpression' => true,
'data' => $this->Js->serializeForm(array(
'isForm' => true,
'inline' => true
))
)));
?>
MY VIEW TIME_PER_PROJECT_ISSUE_TYPE_CHART
<div id="chart_div" >
<?php
echo $this->GoogleChart->createJsChart($timePerProjectIssueTypeChart);
?>
</div>
CONTROLLER
function timePerProjectIssueTypeChart() {
if (!empty($this->request->data['projects'])) {
$id_project = $this->request->data['projects'];
$totalProject = $this->timeSpentPerProjectSpecific(10001, 'Registo.issuetype');
$timeSpent = $this->totalTimeSpentPerProject(10001);
//Setup data for chart
$timePerProjectIssueTypeChart = new GoogleChart();
$timePerProjectIssueTypeChart->type("PieChart");
$timePerProjectIssueTypeChart->options(array('title' => "Percentagem de Tempo (horas) investido em cada Tarefa",
'height' => 300, 'width' => 500));
$timePerProjectIssueTypeChart->columns(array(
//Each column key should correspond to a field in your data array
'issuetype' => array(
'type' => 'string',
'label' => 'Tipo Tarefa'
),
'tempoGasto' => array(
'type' => 'time',
'label' => '% horas'
)
));
//You can also use this way to loop through data and creates data rows:
foreach ($totalProject as $row) {
if ($timeSpent[0][0]['tempogasto'] != 0) {
$percentagemTempoGasto = ($this->timeToHour($row[0]['tempogasto']) / $timeSpent[0][0]['tempogasto']) * 100;
} else {
$percentagemTempoGasto = 0;
}
if (!empty($row['IssueType'])) {
$timePerProjectIssueTypeChart->addRow(array('tempoGasto' => $percentagemTempoGasto, 'issuetype' => $row['IssueType']['pname']));
} else {
$timePerProjectIssueTypeChart->addRow(array('tempoGasto' => $percentagemTempoGasto, 'issuetype' => 'Sem tarefa'));
}
}
//Set the chart for your view
$this->set('totalProject', $totalProject);
$this->set('timeSpent', $timeSpent);
$this->set(compact('timePerProjectIssueTypeChart'));
}
}
I do not put the code of the controllers, because individually tested and are working.
Thanks
Teste com ajax, sem o JS helper:
$(document).ready(function() {
$("#projectsTest").change(function(){
$.ajax({
type: 'POST',
data: { projects: $('#projectsTest').val()},
url: 'timePerProjectIssueTypeChart',
success: funcion() {
$("chart_div").load('timePerProjectIssueTypeChart');
}
})
})
});
E não esqueça de colocar $this->layout = false no controller