Error: The value you selected is not a valid choice - php

 Currently, I am updating the system running on the existing Symfony 2.3 (currently 3.0.9), and I am verifying the operation.
 I want to save the data selected in Form in the DB, but some data that uses ChoiceType cannot be saved due to The value you selected is not a valid choice.
 It seems that the data passed is the same as the system before the update to the DB, but it seems to be rejected.
One thing that seems to be related to the error is that I replaced the numbers and words in the parameters in services.yml.
 This is because what was displayed on the page was a number, although the word was supposed to be displayed.
Could you give me some advice?
Error
shop_keepRequestMinRank => The value you selected is not a valid choice.
shop_prefId => The value you selected is not a valid choice.
Code
ShopController.php
if ($request-> isMethod('PUT')){
if ($form->handleRequest($request)->isValid()){
// save save
$this->get("admin.shopService")->save($shop);
$this->get('session')->getFlashBag()->add('success','Saved shop profile.');
return $this->redirect($this->generateUrl ('ahi_sp_admin_shop_shop_edit'));
} else {
$this->get('session')->getFlashBag()->add('error','Could not save shop profile. Please check your entries.');
}
}
}
Services.yml
parameters:
#member rank
amc_member_rank:
"White": 0
"Navy": 1
"Orange": 2
"Silver": 3
"Black": 4
prefectures:
"Hokkaido": 1
"Aomiriken": 2
Parameters.php
/ **
* Get the prefecture's
*
* #return array Prefectures
* /
public static function getPrefectures()
{
return self::$container->getParameter("prefectures");
}
/ **
* Get the key of the prefecture
*
* #return array Prefectural key
* /
public static function getPrefecturesKeys ()
{
return array_keys(self::getPrefectures());
}
/ **
* Get AMC membership rank
*
* #return array AMC member rank
* /
public static function getAmcMemberRank()
{
return self::$container->getParameter("amc_member_rank");
}
/ **
* Get a key for membership rank
*
* #return array member rank key
* /
public static function getAmcMemberRankKeys()
{
return array_keys(self::getAmcMemberRank());
}
ShopType.php
// Prefectures
$builder->add("prefId", ChoiceType::class, array(
"required"=>true,
"choices"=>Parameters::getParameter("prefectures"),
));
// The lowest rank that can be reserved
$builder->add("keepRequestMinRank", ChoiceType::class, array(
'choices'=>Parameters::getParameter('amc_member_rank'),
'expanded'=>false,
'required'=>true,
));
Version
Cent OS 6.7 PHP 5.6 Symfony3.0.9

In Symfony 2.7 they added choices_as_values option, as the data supplied to a ChoiceType is now reversed (keys with values)
For backward compatibility you must set choices_as_values to false.
For the long run you must reverse all your data arrays for ChoiceType values.
See https://symfony.com/doc/2.7/reference/forms/types/choice.html#choices-as-values
Extra advice: When upgrading major versions read the UPGRADE.md file from the new version and check for Breaking Changes (BC). Moreover, you should have first upgraded to symfony 2.8 as that is a version special made for transitioning from symfony 2 to 3, and firstly fix all the deprecation warnings.

Related

Creating a Transaction Filter in PHP for creating a GetTransactionsRequest object

I am writing a client that makes requests to the DA Ledger. I am following the advice I received in a previous post Doing CRUD on the DA Ledger through a gRPC client.
I need to run the 'GetTransactions' rpc. Doing so requires GetTransactionsRequest object. The GetTransactionsRequest object has a required property called 'filter' which is of type TransactionFilter. I am having trouble creating a transaction filter to meet my needs. The .proto file for it is:
// Used for filtering Transaction and Active Contract Set streams.
// Determines which on-ledger events will be served to the client.
message TransactionFilter {
// Keys of the map determine which parties' on-ledger transactions are being queried.
// Values of the map determine which events are disclosed in the stream per party.
// At the minimum, a party needs to set an empty Filters message to receive any events.
// Required
map<string, Filters> filters_by_party = 1;
}
the one and only field of 'filters_by_party' is required.
Setting this field in php requires the following function:
/**
* Keys of the map determine which parties' on-ledger transactions are being queried.
* Values of the map determine which events are disclosed in the stream per party.
* At the minimum, a party needs to set an empty Filters message to receive any events.
* Required
*
* Generated from protobuf field <code>map<string, .com.digitalasset.ledger.api.v1.Filters> filters_by_party = 1;</code>
* #param array|\Google\Protobuf\Internal\MapField $var
* #return $this
*/
public function setFiltersByParty($var)
{
$arr = GPBUtil::checkMapField($var, \Google\Protobuf\Internal\GPBType::STRING, \Google\Protobuf\Internal\GPBType::MESSAGE, \Com\Digitalasset\Ledger\Api\V1\Filters::class);
$this->filters_by_party = $arr;
return $this;
}
The php function for setting up a values in a mapFiled object is:
/**
* Assign the element at the given key.
*
* This will also be called for: $arr[$key] = $value
*
* #param object $key The key of the element to be fetched.
* #param object $value The element to be assigned.
* #return void
* #throws ErrorException Invalid type for key.
* #throws ErrorException Invalid type for value.
* #throws ErrorException Non-existing key.
*/
public function offsetSet($key, $value)
{
$this->checkKey($this->key_type, $key);
switch ($this->value_type) {
case GPBType::SFIXED32:
case GPBType::SINT32:
case GPBType::INT32:
case GPBType::ENUM:
GPBUtil::checkInt32($value);
break;
case GPBType::FIXED32:
case GPBType::UINT32:
GPBUtil::checkUint32($value);
break;
case GPBType::SFIXED64:
case GPBType::SINT64:
case GPBType::INT64:
GPBUtil::checkInt64($value);
break;
case GPBType::FIXED64:
case GPBType::UINT64:
GPBUtil::checkUint64($value);
break;
case GPBType::FLOAT:
GPBUtil::checkFloat($value);
break;
case GPBType::DOUBLE:
GPBUtil::checkDouble($value);
break;
case GPBType::BOOL:
GPBUtil::checkBool($value);
break;
case GPBType::STRING:
GPBUtil::checkString($value, true);
break;
case GPBType::MESSAGE:
if (is_null($value)) {
trigger_error("Map element cannot be null.", E_USER_ERROR);
}
GPBUtil::checkMessage($value, $this->klass);
break;
default:
break;
}
$this->container[$key] = $value;
}
How do I, for example, set up the parties name 'dealer1' and 'dealer2' as my parties for filters_by_party. I tried the following code:
$parties= new Google\Protobuf\Internal\MapField(Google\Protobuf\Internal\GPBType::STRING,Google\Protobuf\Internal\GPBType::MESSAGE);
$parties->offsetSet(0,"dealer1");
$parties->offsetSet(1,"dealer2");
results in the following error:
PHP Fatal error: Given value is not message. in /home/vantage/damlprojects/loaner_car/php/ledger_client.php on line 85
I don't understand why a 'message'
is required by the filter_by_party 'set' function. I don't know how to write the dealer name in the form of a 'meessage'. It seems doing something that should be simple is very complicated. What is the correct way to set up the input $var to the 'setFiltersByParty' function?
Maybe you can find some information here:
https://developers.google.com/protocol-buffers/docs/reference/php-generated#fields
For map field, I guess it would be something looks like:
$m->getFiltersByParty()["string"] = new Filters();
The code for setting up 'dealer1' and dealer2' should look as follows:
$parties= new Google\Protobuf\Internal\MapField(Google\Protobuf\Internal\GPBType::STRING,
Google\Protobuf\Internal\GPBType::MESSAGE, "Com\Digitalasset\Ledger\Api\V1\Filters");
$partyIdentifier = new Com\Digitalasset\Ledger\Api\V1\Identifier();
$partyIdentifier->setPackageId($the_package_id); //last one from ListPackages()
$partyIdentifier->setEntityName("<Module>"); //from DAML code
$partyIdentifier->setModuleName("<Template>"); //from DAML code
$partyInclusiveFilters = new Com\Digitalasset\Ledger\Api\V1\InclusiveFilters();
$partyInclusiveFilters->setTemplateIds(array($partyIdentifier));
$partyFilters = new Com\Digitalasset\Ledger\Api\V1\Filters();
$partyFilters->setInclusive($partyInclusiveFilters);
$parties->offsetSet("dealer1",$partyFilters);
$parties->offsetSet("dealer2",$partyFilters);
It is important to set the third parameter of the MapField constructor to "Com\Digitalasset\Ledger\Api\V1\Filters". As the protobuf file suggests:
message TransactionFilter {
// Keys of the map determine which parties' on-ledger transactions are being queried.
// Values of the map determine which events are disclosed in the stream per party.
// At the minimum, a party needs to set an empty Filters message to receive any events.
// Required
map<string, Filters> filters_by_party = 1;
}
The filters_by_party is MapField that has a value_type of 'Filter'. 'Filter' is a type of message (see your transaction_filter.proto file), therefore the MapField constructor needs to know what type of message it is.
The dealer name is not being written in the form of a "message" but rather it is a key_value in the the 'filters_by_party' MapField that corresponds to a 'Filter' object. And a 'Filter' is a type of message. I guess 'simple' is a relative term.

Laravel Validation Rule - At least one input value change must be made

I have a model with title, subtitle, date and am building a form that will allow a user to submit a change request.
How can I validate to ensure at least one edit is made comparing the input fields to database values?
I think the below would ensure the title entered is different from the value in 'different:', but how would I only do this for at least one field?
public function rules()
{
return [
'title' => [
'required',
'different:Dynamic Title name here',
'string',
'max:60',
'not_regex:/[\x{1F600}-\x{1F64F}]/u'
],
'subtitle' => [
'string',
'nullable',
'max:90',
'not_regex:/[\x{1F600}-\x{1F64F}]/u'
]
];
}
e.g.
Title, Subtitle, Date fields are shown. A user must edit at least one of them from the current set database values in order to submit.
I don't know your solution, but I'd recommend to take a look at isDirty() function.
/**
* this will return false, because after we get the record from
* database, there's no attribute of it that we changed. we just
* print if it's dirty or not. so it tells us: "I'm clean, nobody has
* changed my attributes at all.
*/
$role = Role::findOrFail(1);
return $role->isDirty();
/**
* lets say We fetched this role with id=1 and its status was 1. what
* this returns is still false, because even though we set the status
* attribute equal to 1, we still didn't change it. It was 1 when we
* received it from the database and it's still 1.
*/
$role = Role::findOrFail(1);
$role->status = 1;
return $role->isDirty();
/**
* now if the status was 1 in the db, and we set it to 2, it will
* print the true.
*/
$role = Role::findOrFail(1);
$role->status = 2;
return $role->isDirty();
You can also pass an argument to isDirty() function which will only check that specific column value.

get variables from routing if more than one hyphens presents

using symfony 3.0 where I want to get the ID from the URL.
/**
* #Route("/pathtocontent/{id}-{name}", defaults={"id"=null,"name"=null},
requirements={"name"="[a-zA-Z0-9\-_\/]+", "id"="\d+"}, name="routingname")
* #Route("/pathtocontent/{name}-{id}", defaults={"id"=null,"name"=null},
requirements={"name"="[a-zA-Z0-9\-_\/]+", "id"="\d+"},
name="routingname_alias")
*/
public function pathAction(Request $request, $id = null) {
}
So I have 2 rules for the same action. The URL can be:
/pathtocontent/Name-part-comes-here-1234
and also could be like that:
/pathtocontent/1234-Name-part-comes-here
The problem is the first case, where the name get all the:
Name-part-comes-here-1234 value and the Id is null
How can I force the first case to parse the Id value out too, so I need to get the Id (1234) from the :
/pathtocontent/Name-part-comes-here-1234
Use just:
#Route("/pathtocontent/{name}/{id}", defaults={"id"=null,"name"=null},
Because use have many hyphens (-)

How to send new password from Magento CSV import of Customers

We have been trying to modify the Customer.php file ( import/export ) to get it to send out the new account details automatically as it imports the customers from a CSV file.
We are working in the right area as we dropped a simple mail() call which was called (we received the emails) for every new row. The problem arises when trying to get it to generate a new random password and send out the new account details - it never sends any mail and we cannot figure out why! Code follows ( Edited from app/code/local/Mage/ImportExport/Model/Import/Entity/Customer.php )
/**
* Update and insert data in entity table.
*
* #param array $entityRowsIn Row for insert
* #param array $entityRowsUp Row for update
* #return Mage_ImportExport_Model_Import_Entity_Customer
*/
protected function _saveCustomerEntity(array $entityRowsIn, array $entityRowsUp)
{
if ($entityRowsIn) {
$this->_connection->insertMultiple($this->_entityTable, $entityRowsIn);
// BEGIN: Send New Account Email
$cust = Mage::getModel('customer/customer');
$cust->setWebsiteId(Mage::app()->getWebsite()->getId());
foreach($entityRowsIn as $idx => $u){
// Failed
$cust->loadByEmail($u['email']);
$cust->setConfirmation(NULL);
$cust->setPassword($cust->generatePassword(8));
$cust->save();
$cust->sendNewAccountEmail();
//$cust->sendPasswordReminderEmail(); // this call doesnt work either
}
// END: Send New Account Email
}
if ($entityRowsUp) {
$this->_connection->insertOnDuplicate(
$this->_entityTable,
$entityRowsUp,
array('group_id', 'store_id', 'updated_at', 'created_at')
);
}
return $this;
}
Inorder to improve performance magento 'caches' object, so when trying to load an object in a loop you either need to load a new instance or call it reset() method
$website_id = Mage::app()->getWebsite()->getId();
foreach($entityRowsIn as $idx => $u){
$cust = Mage::getModel('customer/customer');
$cust->setWebsiteId($website_id);
$cust->loadByEmail($u['email']);
$cust->setPassword($cust->generatePassword(8));
$cust->save();
$cust->sendNewAccountEmail(); // if you are getting 2 email then remove this line
}
If you are load a large number of customers then you may run in to memory issues and my need to look a other technique using reset()
If this code is being run from the Administration section of Magento then you will need to make sure that you set the correct Website ID ( Mage::app()->getWebsite()->getId() will return the incorrect one ).
From the front end this code will work fine but for Admin work you should use '1' or whatever your Front end websites ID is as the getId() method was returning '0' in the Admin area! Small gotcha but had me going for hours!
I had found this script on how to Auto generate password for existing customers
$passwordLength = 10;
$customers = Mage::getModel('customer/customer')->getCollection();
foreach ($customers as $customer){
$customer->setPassword($customer->generatePassword($passwordLength))->save();
$customer->sendNewAccountEmail();
}

How to properly generate exceptions in PHP/Dojo when returning javascript code

I am having difficulty understanding how exceptions are handled when code is fetched dynamically via AJAX and executed via eval. With clientside javascript, it is rather simple, if I have a piece of code such as this
var j = 'some string';
j.propA.x++;
this will raise an exception because propA, which is of type undefined does not have an x. Furthermore, the exception raised is very easy to understand.
Now lets put the above code in a text file, lets call it test.js, and store it on the server. Now lets load it dynamically with Ajax. I am using the following code to load it dynamically
dojo.xhrGet({
url: 'load.php',
handleAs: "javascript",
content : {
fileName : 'test.js'
},
load: function(returnValue) {
/*Do Something*/
},
error: function(errorMessage) {
/*Report Error*/
}
});
Here is a very basic php script for loading the file and returning it as javascript code
<?php
$fileName = $_GET['fileName'];
$handle = fopen($fileName , 'r');
$script = fread($handle, filesize($fileName));
fclose($handle);
echo $script;
?>
In the above dojo.xhrGet call, the error property can be set to a function to display the error message, here is an example of some of the many ways this can be done.
error: function(errorMessage) {
console.error(errorMessage);
console.error(errorMessage.arguments);
console.error(errorMessage.message);
console.error(errorMessage.stack);
console.error(errorMessage.type);
}
Below is an example of the output. Although this output is for a different problem, it highlights how incomprehensible it is:
Cannot read property 'x' of undefined
TypeError: Cannot read property 'x' of undefined
at eval at <anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:3088)
at Object.load (http://192.168.1.8/easel.js:166:6)
at http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:89998
at _144 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36518)
at _142 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36328)
at [object Object].<anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36994)
at _144 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36780)
at _142 (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36328)
at [object Object].<anonymous> (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:36994)
at Object.resHandle (http://o.aolcdn.com/dojo/1.6/dojo/dojo.xd.js:14:92730)
non_object_property_load
I am assuming dojo.xd.js:14 is the line where the eval statement is.
If one knows what they are looking for, the above might suffice. However, is there an easier, or at least a more productive way to deal with exceptions arising in eval?
Here is a somewhat similar question.
Phikin provided a good solution to this problem below so I gave him the bounty. Using his solution, I got an output which looked something like this (I cut it down a bit)
ReferenceError in JS Code detected: (url: module.require.php?module=MainMenu.Bg_S)
easel.js:211Error Message: ReferenceError: apple is not defined
easel.js:213(function(){
return function(args){
dojo.require("Shape");
Module.assert('MainMenu_V');
/**
* The rectangular background of the Main View
* #property MainMenuBg_S
* #type Shape
**/
new Shape({
/**
* Unique descriptive name used when later accessing this shape via '$$()'
* #param name
* #type String
**/
name : 'MainMenu.Bg_S' ,
/**
* Left side of this rectangle
* #param x
* #type Number
**/
x : $$('MainMenu_V').x ,
/**
* Top of this rectangle
* #param y
* #type Number
**/
y : $$('MainMenu_V').y ,
/**
* Width of this rectangle
* #param w
* #type Number
**/
w : $$('MainMenu_V').w ,
/**
* Height of this rectangle
* #param h
* #type Number
**/
h : $$('MainMenu_V').h ,
/**
* Type of this Shape
* #param h
* #type Number
**/
type : shapeType.RECTANGLE ,
/**
* Generate function which contains all the graphics instructions, as well as the contexts
* to preload and initialize. This is currently under development. Backgrounds should NEVER
* have mouse events associated with them as a redraw of a background implies a redraw of
* every single displayObject infront of the background.
* #param generate
* #type method
**/
generate : function (){
var x = this.x << 0 , y = this.y << 0 , h = this.h << 0 , w = this.w << 0 , a = this.a;
this.graphics(contextID.LEAVE).lf([hsl(180,100,60,0.9),hsl(180,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.ENTER).lf([hsl(135,100,40,0.9),hsl(135,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.CLICK).lf([hsl(90,100,40,0.9),hsl(90,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.RCLICK).lf([hsl(90,110,40,0.9),hsl(80,60,20,0.45)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.DBLCLICK).lf([hsl(45,100,40,0.9),hsl(45,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.DBLRCLICK).lf([hsl(10,100,40,0.9),hsl(10,100,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.LPRESS).lf([hsl(110,25,40,0.9),hsl(110,25,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.RPRESS).lf([hsl(110,50,40,0.9),hsl(110,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
this.graphics(contextID.SCROLL).lf([hsl(110,50,40,0.9),hsl(110,50,20,0.75)],[0,1],0,h/2,w,h/2).dr(x,y,w,h).ef();
if (debugFlags.BOUNDINGBOX()){
this.graphics(contextID.ENTER).ss(2).s(rgba(0,255,0,a)).dr(this.boundingBox.softBounds.L +4<<0, this.boundingBox.softBounds.T +4<<0, this.boundingBox.softBounds.w-8<<0 , this.boundingBox.softBounds.h-8<<0).es();
this.graphics(contextID.ENTER).ss(2).s(rgba(255,0,0,a)).dr(this.boundingBox.bounds.L +4<<0, this.boundingBox.bounds.T +4<<0, this.boundingBox.bounds.w-8<<0 , this.boundingBox.bounds.h-8<<0).es();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[0].x+4 , this.boundingBox.points[0].y+4 , 4).ef();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[1].x-8 , this.boundingBox.points[1].y+4 , 4).ef();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[2].x-8 , this.boundingBox.points[2].y-8 , 4).ef();
this.graphics(contextID.ENTER).f(rgba(0,0,255,a)).dc(this.boundingBox.points[3].x+4 , this.boundingBox.points[3].y-8 , 4).ef();
}
},
/**
* Arguments to pass to the mouse initialization function. These will get mixed in (via
* dojo.mixin) to the mouse object. To increase performance, the signalOrderIn has been set to
* NOHIT. This will limit the number of redraws (remember background redraws are extremely
* expensive as they require redrawing everything in the container). The signalOrderOut is
* then set to BLOCK to prvent anything behind the background from receiving mouse signals
* (this is actually unecessary as the only think behind the background is, and always should
* be, the container, which itself has signalOrderIn and signalOrderOut set to NOHIT and BLOCK
* respectively).
* #param mouse
* #type Object
**/
mouse : {
_signalOrderIN : signalFlags.NOHIT ,
_signalOrderOUT : signalFlags.BLOCK
} ,
/**
* All views are initially loaded via Ajax. Generally, views do not have any preconditions, beyond
* that the stage be present. They can, however, and generally do, have modules they require. These
* are called after this view has been created and loaded (load() function call). They are called
* in the order of the sub arrays. In the example below:
* [[A , B , C , D , E , F , G]]
* The 7 modules are requested in that order, but, due to Ajax, they can be loaded in any order.
* In the below example, on the other hand:
* [[A] , [B , C , D , E , F , G]]
* Modules B-G depend on module A, therefore, module A is ordered to be loaded first.
* #property providedModules
* #type Array[Array[String]]
* #protected
**/
providedModules : [[]] ,
/**
* Carries out all the initializations when loading the module
* #method load
* #protected
**/
load : function (){
0/apple;
$$('MainMenu_V').addChild(this);
} ,
/**
* Carries out all memory deallocation when leaving the module (generally only necessary if modules
* were loaded but not added to stage as in the case with cached bitmaps)
* #method leave
* #protected
**/
leave : function (){
}
});
$$('MainMenu.Bg_S')._code="dojo.require(\"Shape\");...";
};
}());
easel.js:217Error triggered by: function (_2bd){return err.call(args,_2bd,_2b7);}
easel.js:220XHR Object:
easel.js:221
Object
args: Object
handleAs: "javascript"
query: null
url: "module.require.php?module=MainMenu.Bg_S"
xhr: XMLHttpRequest
__proto__: Object
easel.js:222Error Object:
easel.js:223
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
dojo.xd.js:14
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
dojo.xd.js:14
ReferenceError
arguments: Array[1]
message: "—"
stack: "—"
type: "not_defined"
__proto__: Error
The only thing it's missing, that I need, is the ability to indicate what line the problem occurred.
Here is a snipped that detectes non-network related errors from an xhr-get request and outputs some information about it in the console.
There is an extra isEvalError() function that goes through all eval-error types... which I am not really proud of. A nicer way could be by getting the parent object of the errorMessage sub-classes.
I think you can ditch isEvalError() generally, because there shouldn´t be any other error possible in this block.
function isEvalError(errorMessage){
return errorMessage.name == "RangeError" ||
errorMessage.name == "ReferenceError" ||
errorMessage.name == "SyntaxError" ||
errorMessage.name == "URIError" ||
errorMessage.name == "TypeError";
}
var foo = dojo.xhrGet({
url: 'stacko.js',
handleAs: "javascript",
load: function(returnValue) {
console.log("load: "+returnValue);
},
error: function(errorMessage,ioargs) {
//request worked fine, this must be a non-network related error
if(ioargs.xhr.readyState == 4 && ioargs.xhr.status == 200) {
if(isEvalError(errorMessage)){
//show eval-error, url request & the JS code that causes the exception
//eval-error types: RangeError,ReferenceError,SyntaxError, URIError, TypeError
console.error(errorMessage.name+" in JS Code detected: (url: "+ioargs.url+")")
console.error("Error Message: "+ errorMessage);
console.error(ioargs.xhr.responseText);
}
//a little reflection - if u want to know who triggered this error
//(although in this case the output is not very helpful )
console.error("Error triggered by: "+arguments.callee.caller.toString());
//last but not least log the error & the xhr-request object for more information
console.error("XHR Object:");
console.error(ioargs);
console.error("Error Object:");
console.error(errorMessage);
}
}
});
It really depends on what you mean "productive way to deal with exceptions". If all you need to do is view the exception contents, a simple
console.log(errorMessage);
will allow you to effortlessly inspect the error object in decent browser like Chrome or Firefox (with Firebug). (Instead of forcing you to do a ton of console.log statements)
An annoying thing about Dojo exceptions inside asynchronous code is that they are always caught and handled so most browser debuggers ignore them. A notable exception to this rule is Chrome, where you can tell the debugger to pause on all exceptions.
BTW: I don't see how Javascript exceptions and Dojo have anything to do with PHP in this case, since they occur on the client side and there is nothing the server can do about them. Also, what the hell are you doing by sending Javascript code in the AJAX? Most of the time a client does a request it will be for data, in plain text, JSON or XML.

Categories