Come back to this after some monthes, with new needs.
I use an other way to load file via CRUD operations : the Javascript' API "File", and store the file (image) in PgSQL database.
Here's the complete code for help to some of you if needed.
The model
Code:
Ext.define('MY_APP.model.annuaire.AnnuaireCadreModel', {
extend: 'Ext.data.Model',
alias: 'model.annuaire_cadre',
requires: [
'Ext.data.field.Integer',
'Ext.data.field.Boolean',
'Ext.data.field.String'
],
fields: [
{
type: 'int',
name: 'id_cadre'
},
{
type: 'boolean',
defaultValue: 0,
name: 'modification'
},
{
type: 'boolean',
defaultValue: 0,
name: 'suppression'
},
{
type: 'string',
name: 'patronyme'
},
{
type: 'string',
name: 'date_de_naissance'
},
{
type: 'string',
name: 'photo'
}
]
});
The store
Code:
Ext.define('MY_APP.store.annuaire.AnnuaireCadre', {
extend: 'Ext.data.Store',
requires: [
'MY_APP.model.annuaire.AnnuaireCadreModel',
'Ext.data.proxy.Rest',
'Ext.data.reader.Json',
'Ext.data.writer.Json'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
remoteFilter: true,
remoteSort: true,
storeId: 'annuaire.AnnuaireCadre',
model: 'MY_APP.model.annuaire.AnnuaireCadreModel',
proxy: {
type: 'rest',
url: 'php/application/app.php/annuaire_cadre',
reader: {
type: 'json',
rootProperty: 'data'
},
listeners: {
exception: {
fn: me.onRestException,
scope: me
}
},
writer: {
type: 'json',
allDataOptions: {
associated: true,
persist: true
}
}
}
}, cfg)]);
},
onRestException: function(proxy, response, operation, eOpts) {
var reponse = Ext.JSON.decode(response.responseText);
Ext.MessageBox.show({
title: reponse.title,
msg: reponse.message,
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
}).center();
}
});
The grid to list the datas
Code:
Ext.define('MY_APP.view.annuaire.listeAnnuCadre', {
extend: 'Ext.grid.Panel',
alias: 'widget.annuaire.listeannucadre',
requires: [
'MY_APP.view.annuaire.listeAnnuCadreViewModel',
'MY_APP.view.annuaire.listeAnnuCadreViewController',
'Ext.grid.column.Action',
'Ext.view.Table',
'Ext.XTemplate'
],
controller: 'annuaire.listeannucadre',
viewModel: {
type: 'annuaire.listeannucadre'
},
cls: 'annuaire_cadre',
tpl: [ //<== some tpl with css to display datas
'<div class="cadre-data">',
'<div class="cadre-line">',
'<div class="cadre-picture">',
'<img src="{photo}">',
'</div>',
'<div class="cadre-content">',
'<div class="cadre-patronyme">',
'{patronyme}',
'</div>',
'<div>',
'{date_de_naissance}',
'</div>',
'</div>',
'</div>',
'</div>'
],
hideHeaders: true,
rowLines: false,
store: 'annuaire.AnnuaireCadre',
columns: [
{
xtype: 'actioncolumn',
getClass: function(v, metadata, r, rowIndex, colIndex, store) {
if (v === false) {
return '';
} else if (v === true) {
return 'modifieGridCls';
}
},
getTip: function(value, metadata, record, rowIndex, colIndex, store) {
if (value === false) {
return '';
} else if (value === true) {
return 'Click to change datas</u></b>';
}
},
isActionDisabled: function(view, rowIndex, colIndex, item, record) {
return !record.data.modification;
},
handler: 'listeAnnuCadreModification',
draggable: false,
resizable: false,
width: 35,
sortable: false,
align: 'center',
dataIndex: 'modification',
menuDisabled: true
},
{
xtype: 'actioncolumn',
handler: 'listeAnnuCadreSuppression',
getClass: function(v, metadata, r, rowIndex, colIndex, store) {
if (v === false) {
return '';
} else if (v === true) {
return 'supprimeGridCls';
}
},
getTip: function(value, metadata, record, rowIndex, colIndex, store) {
if (value === false) {
return '';
} else if (value === true) {
return 'Clito delete datas</u></b>';
}
},
isActionDisabled: function(view, rowIndex, colIndex, item, record) {
return !record.data.suppression;
},
draggable: false,
resizable: false,
width: 35,
sortable: false,
align: 'center',
dataIndex: 'suppression',
menuDisabled: true
},
{
xtype: 'gridcolumn',
renderer: 'renderNomColumn',
flex: 1,
dataIndex: 'patronyme'
}
]
});
The form to add datas
Code:
Ext.define('MY_APP.view.annuaire.FormAnnuCadre', {
extend: 'Ext.form.Panel',
alias: 'widget.annuaire.formannucadre',
requires: [
'MY_APP.view.annuaire.FormAnnuCadreViewModel',
'MY_APP.view.annuaire.FormAnnuCadreViewController',
'Ext.form.field.Display',
'Ext.form.field.ComboBox',
'Ext.form.field.File',
'Ext.form.field.Date',
'Ext.form.field.Hidden',
'Ext.Img',
'Ext.grid.Panel',
'Ext.view.Table',
'Ext.grid.column.Date',
'Ext.grid.plugin.RowEditing',
'Ext.toolbar.Toolbar',
'Ext.button.Button'
],
controller: 'annuaire.formannucadre',
viewModel: {
type: 'annuaire.formannucadre'
},
id: 'id_FormAnnuCadre',
scrollable: false,
bodyPadding: 10,
defaultListenerScope: true,
initConfig: function(instanceConfig) {
var me = this,
config = {
items: [
{
xtype: 'displayfield',
anchor: '100%',
value: 'Some text or help'
},
{
xtype: 'container',
margin: '0 0 10 0',
layout: 'column',
items: [
{
xtype: 'container',
columnWidth: 0.9,
layout: 'anchor',
items: [
{
xtype: 'combobox',
anchor: '80%',
fieldLabel: 'Agent',
labelAlign: 'right',
labelWidth: 150,
name: 'id_cadre',
allowBlank: false,
emptyText: '3 or 4 char of the name...',
displayField: 'libelle_utilisateur',
minChars: 3,
store: 'administration.utilisateur',
typeAhead: true,
valueField: 'id_utilisateur'
},
{
xtype: 'filefield',
anchor: '80%',
id: 'id_photo_path',
fieldLabel: 'Photo',
labelAlign: 'right',
labelWidth: 150,
listeners: {
change: 'onAttachmentChange' //<== to show the image after choosing it
}
},
me.processDate_de_naissance({
xtype: 'datefield',
anchor: '50%',
fieldLabel: 'Date de naissance',
labelAlign: 'right',
labelWidth: 150,
name: 'date_de_naissance',
showToday: false
}),
{
xtype: 'hiddenfield',
id: 'id_photo',
name: 'photo'
}
]
},
{
xtype: 'image', //<== where the image will be shown
height: 120,
id: 'photo_thumb',
width: 120,
src: '%22%22'
}
]
},
{
xtype: 'container',
padding: 10,
layout: {
type: 'hbox',
align: 'middle',
pack: 'center'
},
items: [
{
xtype: 'button',
margin: '0 10 0 0',
width: 150,
iconCls: 'x-fa fa-remove',
text: 'Annuler',
listeners: {
click: {
fn: 'cancelEdit',
scope: 'controller'
}
}
},
{
xtype: 'button',
formBind: true,
disabled: true,
margin: '0 0 0 10',
width: 150,
iconCls: 'x-fa fa-check',
text: 'Enregistrer',
listeners: {
click: {
fn: 'save',
scope: 'controller'
}
}
}
]
}
]
};
if (instanceConfig) {
me.self.getConfigurator().merge(me, config, instanceConfig);
}
return me.callParent([config]);
},
processDate_de_naissance: function(config) {
config.maxValue = Ext.Date.add(new Date(), Ext.Date.YEAR, -18);
config.minValue = Ext.Date.add(new Date(), Ext.Date.YEAR, -67);
config.value = Ext.Date.add(new Date(), Ext.Date.YEAR, -18);
return config;
},
onAttachmentChange: function(filefield, value, eOpts) { //<== the function to show the image in the image field, using the Javascript' API "File"
var file = filefield.fileInputEl.dom.files[0],
reader;
if (file === undefined || !(file instanceof File)) {
return;
}
reader = new FileReader();
reader.onload = function (event) {
Ext.getCmp('photo_thumb').setSrc(event.target.result);
};
reader.readAsDataURL(file);
}
});
The ViewController's form
Code:
Ext.define('MY_APP.view.annuaire.FormAnnuCadreViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.annuaire.formannucadre',
cancelEdit: function(button, e, eOpts) {
this.getView().getForm().reset();
},
save: function(button, e, eOpts) {
var form = this.getView().getForm(),
values,
model,
store = Ext.getStore('annuaire.AnnuaireCadre');
if (form.isValid()) {
// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
//*******************************************************************************************************
// We use the Javascript' API "File" to read the file as dataurl
// Then put the data url in the field "id_photo"
// Then add the form's values in the store's model
// Then sync the store
//*******************************************************************************************************
var file = Ext.getCmp('id_photo_path').fileInputEl.dom.files[0],
reader;
if (file === undefined || !(file instanceof File)) {
return;
}
reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (event) {
Ext.getCmp('id_photo').setValue(event.target.result);
values = form.getValues();
model = Ext.create('model.annuaire_cadre', values);
store.add(model);
store.sync({
success: function(batch, options) {
response = Ext.decode(batch.operations[0].getResponse().responseText);
Ext.Msg.show({
title: response.title,
msg: response.message,
buttons: Ext.Msg.OK,
scope: this,
icon: Ext.Msg.INFO
});
}
});
};
} else {
alert('The File APIs are not fully supported in this browser.');
}
} else {
Ext.Msg.show({
title: 'Error',
msg: 'Some erros, please check !',
buttons: Ext.Msg.OK,
animateTarget: button,
scope: this,
icon: Ext.Msg.ERROR
});
}
}
});
In the PgSQL database, use a BYTEA column to store the data (the name of the column i've choosen : photo)
In PHP script, think to escape before inserting :
Code:
pg_escape_bytea($_POST['photo'])
When selecting in the SQL :
Code:
SELECT ENCODE(photo, 'base64') as photo
When sending dats from PHP :
Code:
base64_decode($my_pg_query_result["photo"])