how to update an object in symfony 3? - ajax

I want to update profile infos, but after everything I have done nothing happened..
I work using ajax to send data from twig to updateAction ..
ajax :
$(document).ready(function ()
{
$("#btnEnregistrer").click(function () {
var URL = "{{path('profile_update')}}";
var n = $('#txtNom').val();
var nAr = $('#txtNomAr').val();
var pre = $('#txtPrenom').val();
var preAr = $('#txtPrenomAr').val();
var passOld = $('#txtPassOld').val();
var pass1 = $('#txtPassNew').val();
var pass2 = $('#txtPassNew2').val();
var dateN = $('#txtDateN').val();
var ad = $('#txtAdresse').val();
var adAr = $('#txtAdresseAr').val();
var mob = $('#txtMobile').val();
var fixe = $('#txtFixe').val();
var sexe ;
if($('#rbHomme').is(':checked'))
sexe="Homme";
else
if($('#rbFemme').is(':checked'))
sexe="Femme";
var DATA = 'nom='+n+'&nomAr='+nAr+'&prenom='+pre+'&prenomAr='+preAr+'&sexe='+sexe+'&passOld='+passOld+'&passNew='+pass1+'&passNew2='+pass2+'&dateN='+dateN+'&adresse='+ad+'&adresseAr='+adAr+'&mobile='+mob+'&fixe='+fixe;
$.ajax({
type: "POST",
url: URL,
data: DATA,
cache: false
});
});
});
{{path('profile_update')}} is the route of updateAction :
public function updateAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
if ($request->isXmlHttpRequest()) {
$utilisateur = $this->get('session')->get('user');
$Vparam = $em->getRepository('ParametersBundle:Parameter')->findOneBy(['id' => $utilisateur->getVille()]);
$utilisateur->setNom($request->get('nom'));
$utilisateur->setNomAr($request->get('nomAr'));
$utilisateur->setPrenom($request->get('prenom'));
$utilisateur->setPrenomAr($request->get('prenomAr'));
$s = $request->get('sexe');
if($s == "Homme")
{
$utilisateur->setSexe("Homme");
$utilisateur->setSexeAr("ذكر");
}
else
{
$utilisateur->setSexe("Femme");
$utilisateur->setSexeAr("أنثى");
}
$utilisateur->setDateN($request->get('dateN'));
$utilisateur->setAdresse($request->get('adresse'));
$utilisateur->setAdresseAr($request->get('adresseAr'));
if($request->get('passOld') !="" && $request->get('passNew') !="" && $request->get('passNew2') !="")
{
if($request->get('passOld') == self::getHash($utilisateur->getPassword(), $utilisateur->getSalt()))
{
if($request->get('passNew') == $request->get('passNew2'))
{
$utilisateur->setPassword(self::getHash($request->get('passNew'), $utilisateur->getSalt()));
}
else
{
return $this->redirectToRoute('ens_profile');
}
}
else
{
return $this->redirectToRoute('ens_profile');
}
}
$em->flush();
return $this->redirectToRoute('ens_profile');
}
route.yml :
persons_connexion:
path: /connexion
defaults: { _controller: PersonsBundle:Default:connexion }
persons_deconnexion:
path: /deconnexion
defaults: { _controller: PersonsBundle:Default:deconnexion }
ens_profile:
path: /Enseignant/profile
defaults: { _controller: PersonsBundle:Enseignant:profile }
profile_update:
path: /Enseignant/profile/miseajour
defaults: { _controller: PersonsBundle:Enseignant:update }
the parameters show up in Symfony Profiler as POST Parameters ..
but when I look at the table in database, I found that nothing happened ..
So, what is the problem? and how can I solve it?

First, you're doing something really odd...
Instead of having javascript fetch your user data in the DOM, why don't you use a form and submit it directly?
You seems rather new to Symfony, so I will suggest the best method for you to learn how Symfony does things... Use the commands lines to generate entities, controllers, forms, and so on...
Here is a list of the most user commands to work with Symfony:
Create a bundle
php bin/console generate:bundle
Create an entity
php bin/console doctrine:generate:entity
Refresh all entities getters and setters within a bundle
php bin/console doctrine:generate:entities *NameBundle*
Refresh one entity getters and setters
php bin/console doctrine:generate:entities *NameBundle:Entity*
Check entities relations and and database squeleton
php bin/console d:s:v
Create entity form type
php bin/console doctrine:generate:for
Create entity controller, form type and view
php bin/console doctrine:generate:crud --with-write
Dump SQL changes into console.
php bin/console doctrine:schema:update --dump-sql
Use before updating skeleton to check if every is as you want it.
Apply SQL changes
php bin/console doctrine:schema:update --force
List all existing routes into the console.
php bin/console debug:router
Clear production cache
php bin/console cache:clear --no-warmup --env=prod
Clear developemnt cache
php bin/console cache:clear --no-warmup --env=dev'
Because it make things easier, I would suggest you to use annotation for routes instead of yml.
For your code, it's a real mess and not valid as is...
If you were using a form, this is how the basic edit action should looks like
public function editAction(Request $request, User $user) {
$editForm=$this->createForm(UserType::class, $user);
$editForm->handleRequest($request);
if($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()
->getManager()
->flush();
return $this->redirectToRoute('_edit', array('id'=>$user->getId()));
}
return $this->render('security/edit.html.twig', array(
'user'=>$user,
'edit_form'=>$editForm->createView(),
));
}
You code is missing the form part, and is really dangerous as is...
As a good example, you don't submit any form token, which will result in a fail when you try to update database.
I'm afraid that providing help on your code it quite impossible as you're not using symfony as you should.

You need to $em->persist($utilisateur) before the flush if it's not coming from your entity manager.

Related

How to access image from storage

I have a file saved in storage/app/uploads and I would like get this this image saved and show with img src tag.
But I can't
I am trying:
public function getSlider(Request $request)
{
$slider = Slider::find( $request->input('id') );
$slider->imagem = storage_path('storage/app/uploads/'.$slider->imagem);
return response()->json( $slider );
}
And I am trying show with jquery and javascript
function getSliders() {
$.ajaxSetup({
headers: {'X-CSRF-TOKEN' : $('#token').val() }
})
$.ajax({
url: "{{ route('site.getSlider') }}",
type: "post",
dataType: "json",
data: {
id: $('#id').val()
}
}).done( r => {
console.log('r',r)
$('#description').val( r.description )
setImage( r.image )
})
}
And setting Image
function setImage( image ){
var newImage = document.createElement('img');
newImage.setAttribute('src', image);
newImage.width = 500;
newImage.heigth = 200;
document.getElementById("photo").innerHTML = newImage.outerHTML;
}
When I want access image from public/img I use
<img src="{{ URL('img/myImage.png') }}">
But I want to access from storage/app/uploads
This return the file route (no url) (if you see the log it says /var/www.... etc)
storage_path('storage/app/uploads/'.$slider->imagem);
You should use asset helper to create URL of image
asset( 'storage/app/uploads/'.$slider->imagem);
Before this you need to run this command to create symbolic link to storage folder from public folder.
php artisan storage:link
Please try this and let me know how it works :)
try save your images in public folder instead of storage
its simple you can access it by using public_path() function.
Firstly, run this command:
php artisan storage:link
Then in any view you can access your image with the help of url helper.
url('storage/app/uploads');

How to prevent validate function call while calling model.save in backbone JS

I have a backbone view where I call model.save to create/updated date submitted in the form. Before calling the save I explicitly call model.isValid(true) to validate the form fields then I process the form data to make it ready for API expected format (by adding or modifying additional fields) and then make call to mode.save function which is again triggering validate function where the validations are getting failed due to the modified data. As I have already called the isValid function explicitly, I want to prevent the call again during save. How can I do it in backbone. Here is sample code.
var data = Backbone.Syphon.serialize($(e.currentTarget).closest('form.my_form')[0]));
this.model.set(data);
if(this.model.isValid(true)) {
data['metas'] = this.context.metaData;
data['metas'][0]['locale'] = this.parentObj.model.get('locale');
data['metas'][0]['name'] = data['name'];
delete data['name'];
}
var tempDynAttrs = [];
if(data['dynamicAttributes']){
$.each(data['dynamicAttributes'], function(index,obj) {
if(obj['attributeValue'] !== null && obj['attributeValue'] !== undefined ) {
tempDynAttrs.push({
attributeName: obj['attributeName'],
attributeValue: [obj['attributeValue']],
locale: data['defaultLocale'],
status: 'active'
});
}
});
}
data['dynamicAttributes'] = tempDynAttrs;
this.model.save(data, {
url: this.model.url(),
patch: true,
success : function(model, response) {
$('#headerMessage').html('Data is updated successfully');
},
error : function(model, response) {
$('#headerMessage').html('Error updating data');
}
});
} else {
$('#formPanel').animate({
scrollTop: $('.has-error').first().offset().top-50
}, 100);
return false;
}
Try passing {validate:false} in the save options, like
book.save({author: "Teddy"}, {validate:false});
According to change log of version 0.9.10:
Model validation is now only enforced by default in Model#save and no longer enforced by default upon construction or in Model#set, unless the {validate:true} option is passed.
So passing {validate:false} should do the trick.

Loading "knockout.mapping" plugin using require.js

I am creating an MVC3 application, with requireJS. In my views I need to convert the Model object into a knockout viewmodel object. So I need to use knockout and knockout.mapping libraries.
My application is designed in the following way,
1). All the script files are categorized into folders
Scripts/app/home/ - contains the scripts for the views in Home controller.
Scripts/lib/ - contains the scripts like jQuery, knockout,knockout.mapping, requirejs etc
2). In the "_Layout.cshtml" I am referencing "require.js" like this.
<script src="#Url.Content("~/Scripts/lib/require.js")" type="text/javascript"></script>
3). To configure the require.js settings I am using a different script file called "common.js" (Scripts/lib/common.js)
require.config(
{
baseUrl: "/Scripts/",
paths:{
jquery: "lib/jquery-2.0.3",
ko: "lib/knockout-2.3.0",
komapping: "lib/knockout.mapping"
}
});
4). This is my index.js file which is in 'Scripts/app/home/"
define(['ko', 'komapping'], function (ko, komapping) {
var person = function () {
var self = this;
self.getPersonViewModel = function (data) {
return ko.mapping.fromJS(data); ;
};
};
return { Person: person };
});
5). This is my "Index" action method in the "Home" controller
public ActionResult Index()
{
var person = new Person
{
Id = 1,
Name = "John",
Addresses = new List<Address>(new[]{new Address{Country = "Country 1", City = "City 1"}})
};
return View(person);
}
6). Finally this is my "Index" view
#model MMS.Web.Models.Person
<script type="text/javascript">
require(["/Scripts/common/common.js"], function () {
require(["app/home/index"], function (indexJS) {
var person = new indexJS.Person();
var vm = person.getPersonViewModel(#Html.Raw(Json.Encode(Model)));
});
});
</script>
The problem which I am facing is when loading the index.js file, I get a script error that the knockout.js cannot be loaded.
Failed to load resource: the server responded with a status of 404 (Not Found) - http:///Scripts/knockout.js
But if I remove the dependency of "komapping" inside the "index.js" file it loads correctly, but then I cannot use the mapping functionality.
I had a look inside these links, but couldn't find a solution,
Knockout.js mapping plugin with require.js and
https://github.com/SteveSanderson/knockout.mapping/issues/57
Your help, suggestions are much appreciated. Thanks!
I had the same issue. The problem is that the knockout.mapping defines a knockout dependency, so you need to satisfy this one when you load the script.
Here is how you should load your mapping stuff
require.config(
{
baseUrl: "/Scripts/",
paths:{
jquery: "lib/jquery-2.0.3",
knockout: "lib/knockout-2.3.0",
komapping: "lib/knockout.mapping"
},
shim: {
komapping: {
deps: ['knockout'],
exports: 'komapping'
}
}
});
Then in my case, I use an index.js file with a requirejs call like the following
requirejs(['jquery', 'knockout', 'komapping'], function($, ko, komapping){
ko.mapping = komapping;
//Do other stuff here
});

Codeigniter rest issue with backbone

I just started using rest library wrote by Phil Sturgeon. I started using it by writing some simple examples. I short of get 'post' and 'get' work, but not for put and delete. I have some questions based on the code below.
// a simple backbone model
var User = Backbone.Model.extend({
urlRoot: '/user',
defaults:{
'name':'John',
'age': 17
}
});
var user1 = new User();
//user1.save(); // request method will be post unless the id attr is specified(put)
//user1.fetch(); // request method will be get unless the id attr is specified
//user1.destroy(); // request method will be Delete with id attr specified
In my CI REST controller
class User extends REST_Controller
{
public function index_get()
{
echo $this->get(null); //I can see the response data
}
public function index_post()
{
echo $this->post(null); //I can see the response data
}
public function index_put()
{
}
public function index_delete()
{
}
}
Basically, the get and post in the controller will be called when I save a model or fetch a model. With a id specified in the model, I can make a put or delete request to the server using model.save() and model.destroy(). however, I got a server error. it looks like index_put or index_delete can not be called. does anyone know How I can handle:
put request in the controller
delete request in the controller
get a single record with id specified
From the git, I only saw him to list index_post and index_put. there is no index_put and index_delete demo. should anyone can help me out? thanks
I faced the same exact problem, it looks like that DELETE, PUT, PATCH methods are not fully supported by browsers/html/server yet. You may want to look at this stack overflow question: Are the PUT, DELETE, HEAD, etc methods available in most web browsers?
A simple solution would be to change the methodMap of backbone line 1191 to the following:
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var methodMap = {
'create': 'POST',
'update': 'POST', //'PUT',
'patch': 'POST', //'PATCH',
'delete': 'POST', //'DELETE',
'read': 'GET'
};
and then include the action type as an attribute of the model
var Person = Backbone.Model.extend({
defaults:{
action_type : null,
/*
* rest of the attributes goes here
*/
},
url : 'index.php/person'
});
now when you want to save a model, do the following
var person = new Person({ action_type: 'create' });
person.set( attribute , value ); // do this for all attributes
person.save();
in the application/controllers folder you should have a controller called person.php with class named Person extending REST_Controller, that has the following methods:
class Person extends REST_Controller {
function index_get() { /* this method will be invoked by read action */ }
/* the reason those methods are prefixed with underscore is to make them
* private, not invokable by code ignitor router. Also, because delete is
* might be a reserved word
*/
function _create() { /* insert new record */ }
function _update() { /* update existing record */ }
function _delete() { /* delete this record */ }
function _patch () { /* patch this record */ }
function index_post() {
$action_type = $this->post('action_type');
switch($action_type){
case 'create' : $this->_create(); break;
case 'update' : $this->_update(); break;
case 'delete' : $this->_delete(); break;
case 'patch' : $this->_patch(); break;
default:
$this->response( array( 'Action '. $action_type .' not Found' , 404) );
break;
}
}
}
Having said that, this solution is an ugly one. If you scroll up in the backbone implementation, you will find the following code at line 1160:
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
// And an `X-HTTP-Method-Override` header.
if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
params.type = 'POST';
which means you need to set the emulate options of backbone configurations. add the following lines to your main.js
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;
To test the effect of that, I created a simple model and here are the results
you need a controller called Api in applications/controllers folder, in a file named api.php
<?php defined('BASEPATH') OR exit('No direct script access allowed');
require_once APPPATH.'/libraries/REST_Controller.php';
class Api extends REST_Controller
{
function index_get()
{
$this->response(array("GET is invoked"));
}
function index_put()
{
$this->response(array("PUT is invoked"));
}
function index_post()
{
$this->response(array("POST is invoked"));
}
function index_patch()
{
$this->response(array("PATCH is invoked"));
}
function index_delete()
{
$this->response(array("DELETE is invoked"));
}
}
and in your js/models folder, create a model called api_model.js
var Api = Backbone.Model.extend({
defaults:{
id: null,
name: null
},
url: "index.php/api/"
});
var api = new Api();
api.fetch({ success: function(r,s) { console.log(s); } }); // GET is invoked
api.save({},{ success: function(r,s) { console.log(s); } }); // POST is invoked
//to make the record old ( api.isNew() = false now )
api.save({id:1},{ success: function(r,s) { console.log(s); } }); // PUT is invoked
api.destroy({ success: function(r,s) { console.log(s); } }); //DELETE is invoked
I don't know how to do patch, but hope this helps.
Edit
I found out how to do patch, which is not included in the REST implementation of code ignitor. In REST_Controller line 39, you will find the following,
protected $allowed_http_methods = array('get', 'delete', 'post', 'put');
you need to add 'patch' at the end, to accept this method, also, after doing that add this code
/**
* The arguments for the PATCH request method
*
* #var array
*/
protected $_patch_args = array();
also, you need to add the following code to parse patch arguments:
/**
* Parse PATCH
*/
protected function _parse_patch()
{
// It might be a HTTP body
if ($this->request->format)
{
$this->request->body = file_get_contents('php://input');
}
// If no file type is provided, this is probably just arguments
else
{
parse_str(file_get_contents('php://input'), $this->_patch_args);
}
}
Now, according to backbone docs, you need to pass {patch: true} to send a PATCH method, when you call the following line, you execute a patch:
api.save({age:20},{patch: true, success: function(r,s) { console.log(s); } });
// PATCH is invoked

Basic implementation of ajax in magento

I am a newbie in magento and trying to implement ajax,but can't find a proper tutorial to follow. Could anyone provide me some reference or guide me to where i would be able to find it?
Don't know a tutotial but I can explain you bit what I implemented in a project a month back.
I created a controller on which we can fire an AJAX request on a specific action. In this case the getoptionsAction in the IndexController of our custom Offerte module.
The getoptionsAction in my controller takes a product_id and loads the options for the product. It builds the HTML and echo's this on function end.
In phtml file I have following code to invoke the AJAX request and update html-object in frontend:
function get_options(prod_id){
var product_options = $('product_options');
var prod_id = $('product').getValue();
new Ajax.Updater('product_options',
'<?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB); ?>offerte/index/getoptions',
{ method: 'get',parameters: {prod_id: prod_id, type: 'get_regular_options' } ,
onCreate: function(){
$('loading-img-options').show();
},
onComplete: function (t) {
$('loading-img-options').hide();
$('product_options').show();
}
});
}
the above function uses Ajax.Updater. You can also use Ajax.Request to get the result to juggle with.
function stripslashes(str) {
return str.replace(/\\'/g,'\'').replace(/\"/g,'"').replace(/\\\\/g,'\\').replace(/\\0/g,'\0');
}
function get_products(){
product = $('product');
cat_id = $('category').value;
new Ajax.Request('<?php echo Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB); ?>offerte/index/getproducts',
{method: 'get', parameters: {cat_id: cat_id, mode: 'offerte'},
onCreate: function(){
$('product-loading').show();
$('product_options').hide();
},
onSuccess: function(t) {
resp = jQuery.parseJSON(t.responseText);
$('prod-container').innerHTML = resp.options ? stripslashes(resp.options) : '<?php echo $this->__('No options found') ?>';
$('product-loading').hide();
}
});
}
(please note I use JQuery to parseJSON. You can also use String.evalJSON, but I was lazy here :-)
Using Ajax.Request you need to return the result from the controller as JSON. I used the code below in my controller to return JSON to our phtml to use in the onSuccess Callback function above:
$this->getResponse()->setBody(Zend_Json::encode($result));
Hope this is of any help

Resources