So I am working with some numbers which are to be formatted with user's preferred currency format, but ran into a huge wtf and wanted to see how other symfonians handled the sitch.
Using the NumberFormatter helper there is a format_currency function I can call which looks like this:
function format_currency($amount, $currency = null, $culture = null)
{
if (null === $amount)
{
return null;
}
$numberFormat = new sfNumberFormat(_current_language($culture));
return $numberFormat->format($amount, 'c', $currency);
}
And the signature of sfNumberFormat::format looks like:
function format($number, $pattern = 'd', $currency = 'USD', $charset = 'UTF-8')
See the problem? The format_currency signature allows a default null currency value if no currency value is passed, which then overrides the default currency value of the sfNumberFormat::format signature.
My goals here are to set the user's preferred currency once, and only have to pass the number to the format_currency function, as it makes 0 sense to pass in the currency value for X number of calls.
What I am thinking, is adding a new user attribute which will store the user's preferred currency, then copying the NumberFormat code into my own lib/helper and referencing the user's attribute to be passed into the sfNumberFormat::format call.
Any symfonian solve this another way?
The reason why you can pass the currency to every call to the helper is that you can have multiple currencies used for one user, regardless of his/her culture settings.
I also don't see a problem in passing the currency to the each helper call.
In fact if you create a helper which will rely on a session attribute you will make a strong coupling between the user object and the helper, which I don't thing is right. How do you plan to retrieve the attribute inside the helper? You will either have to call sfContext::get (which should generally be avoided) or pass the user object to the helper (which is exactly the same as passing the attribute, or even worse ;) ).
So I ended up just copying and pasting the source NumberHelper functions into my own lib/helper/NumberHelper.php and changed the signature of currency_helper like this:
// Before
function format_currency($amount, $currency = null, $culture = null)
// After
function format_currency($amount, $currency = 'USD', $culture = null)
This allows $currency to pass through to sfNumberFormat::format with the same value (usd), vs passing null.
Related
In my reference class, I have a field m_params which is of the type list. Whenever the user changes something inside that last, I want to do some sort of type checking. That is, I have another list that holds types of the required values in m_params, just like id = "character. In order to implement this type checking, i wrote the following function to let the user set key-value pairs inside the list.
MyClass$methods(
set_param = function(key, value) {
# do some type checking! ...
if (is(m_params, "uninitializedField")) {
m_params <<- list()
}
m_params[[key]] <<- value
}
)
This works, but the user can still use MyClass()$m_params <- list(id=5), which bypasses type checking. Is there any way to prevent the user from using "$" to set fields or at least override the .self$... functions?
In my firebase i have a collection, inside there is a document, and inside there is an object :
object 1
key1:value
key2:value
key3:value
I would like to only update certain keys inside an object say
object1 - key1 and key2.
to do that, i need notation.
the problem is that I pass a parameter to the function that save :
function updateit(product,target)
{
db.collection("Stores").doc(target).update({
product
})
So here if I pass a product that contains only key 1, it will override the previous.
So, I tried to pass this object with notation :
product["product"+".title"] = "xxxxx"; // a new pair in product to pass
and it didn't work, it will save a new object (override) with fields like :
product
product.title=xxxxx
How should you do such a simple thing ?
ok obviously, this is the answer :
db.collection("Stores").doc(targetStore).update(
product // no {} around 'product', not as object!
)
see the comment that explains it all.
I would like to learn how Flow decides what type to use for a generic type, and if there is a way to control at what level the generic type gets inferred (what I mean by this is explained further down).
This question is inspired by How to type a generic function that returns subtypes. I think there is a distinction between the two questions because this one focuses on understanding how T is chosen, where as the linked on is focuses on typing the return type of a function.
The identity function is a great example to dissect. Its type is fairly straightforward
function identity<T>(value: T): T;
This seems like enough information to know what the implementation should be. However, I feel like this type is insufficient to know what the identity function actually does. For example, we could have (as the linked question tries to do),
function identity<T>(value: T): T {
if (typeof value === 'string') {
return '';
}
return value;
}
Try Flow
This does not typecheck, with Flow complaining about returning the empty string. However, I would imagine in many languages that this would be fine--we are returning a string when a string was inputted, otherwise we are returning the original value of type T--but for some reason Flow does not like this.
My confusion is compounded by both this answer, where we can return value.substr(0, 0) instead of the empty string and Flow will no longer complain, and by the inability to return a strictly equal value,
function identity<T>(value: T): T {
if (value === '') {
return '';
}
return value;
}
Try Flow
I think a major reason for this discrepancy is that literals can act like types in Flow, in addition to the "JavaScript type". For example,
const x: 5 = 5; // literal type
const x: number = 5; // JavaScript type
are both valid. However, this means that when we have a function of type T => T, we do not know if Flow is inferring the literal or JavaScript type as the type.
I would like to know if there is some way of either knowing what Flow infers for generic types in a function or if there is a way to scope the generic type to be at the "literal" level or "JavaScript" level. With this ability, we could type function that coerces values to the default value for that type (i.e., strings would go to the empty string, numbers would go to 0). Here the type of the function would effectively be T => T, but hopefully Flow could be prevented from complaining about returning the default values.
Hoping to shed a little light here on what's going on, if not answer the question directly.
Let's take your first example first of all:
function identity<T>(value: T): T {
if (typeof value === 'string') {
return '';
}
return value;
}
The function signature is identity<T>(T): T. This is basically saying:
We are creating a new type T which could be anything (<T>).
Our function is going to receive a single argument of type T.
Our function is going to return a value of type T.
From this point forward, none of these restrictions are going to change, and the type of T is also not going to change. identity must return the exact type of T, not a subset of its type. Let's look at why.
identity<'some string'>('some string');
In this case the type of T is the literal type, 'some string'. In the case of this invocation of the above function, we would find that typeof value === 'string' and attempt to return '', a string. string, however, is a supertype of T which is 'some string', so we have violated the contract of the function.
This all seems rather contrived in the case of simple strings, but it's actually necessary, and much more obvious when scaling up to more complex types.
Let's look at a proper implementation of our weird identity function:
function identity<T>(value: T): T | string {
if (typeof value === 'string') {
return '';
}
return value;
}
A return type of T can only be satisfied by something which exactly matches T, which in the case of our signature can only be value. However, we have a special case where identity may return a string, so our return type should be a union of T | string (or, if we wanted to be super specific, T | '').
Now let's move on to this second example:
function identity<T>(value: T): T {
if (value === '') {
return '';
}
return value;
}
In this case, flow just doesn't support value === '' as a refinement mechanism. Refinement in flow is very picky, I like to think of it as a list of a few simple regular expressions that are run over my code. There's really only way to refine the type to a string, and that's by using typeof value === 'string'. Other comparisons won't refine to string. There's definitely also some wonkiness around refining generics, but something like this works fine (the refinement does, it still exhibits the previous generic-related error, of course):
function identity<T>(value: T): T {
if (typeof value === 'string' && (value: string) === '') {
return '';
}
return value;
}
(Try)
As for the substr example, that definitely looks like a bug to me. It seems you can do the same with any method on String that returns a string, such as concat or slice.
I would like to know if there is some way of either knowing what Flow infers for generic types in a function
Within the function body flow doesn't really infer the type of a generic. A generic has a concrete definition (T is T, essentially an unknown type, unless it has bounds, in which case it is an unknown type that matches those bounds). Flow may infer the types of parameters going into invocations of the function, but that should have no bearing on how the functions are written.
or if there is a way to scope the generic type to be at the "literal"
level or "JavaScript" level. With this ability, we could type function
that coerces values to the default value for that type (i.e., strings
would go to the empty string, numbers would go to 0). Here the type of
the function would effectively be T => T, but hopefully Flow could be
prevented from complaining about returning the default values.
The problem here is that this would no longer be T => T. As I've shown above, breaking such an implementation is trivial.
i have a question about the validate prop.
Suppose we (.....)
In the component we define this:
<Field>
validate = {validate}
</Field>
Why cant we write validate={validate(value)} or why is not correct to write something like this: validate={()=> validate(value)}
Thanks!
The validate prop on Field takes a function (or an array of functions) which should be used to validate the incoming field value. So you can't write validate={ someCustomValidator(value) } unless the someCustomValidator function is a function you have defined that in turn returns a function.
Using validate={()=> someCustomValidator(value)} should work, but doesn't make much sense in the context of your example (where does value come from?). If you use validate={(value)=> someCustomValidator(value)} instead, that makes more sense, but this is problematic because this will create a new function each time the component with the Field re-renders. And according to the documentation:
Note: if the validate prop changes the field will be re-registered.
which is probably not what you want to happen.
So, using
// validation
const someCustomValidator = value => {
// give error roughly half of the time
return Math.random() < 0.5 ?
undefined : // validation is ok
'Validation failed'; // this will be available in meta.error
}
// somewhere else
<Field validate={someCustomValidator} />
is the correct way of using it. But note that Field doesn't internally know what to do to display potential validation errors. That you have to solve yourself. See https://redux-form.com/7.0.4/examples/fieldlevelvalidation/ for an example.
I've got a backbone collection and I'm trying to filter by an id within the attributes
basically, a user has classes, and the class has a location_id, and I want to filter by the location id. My collection looks like this to give you an idea.
-user
-models
-0
-attributes
-location_id
-1
-attributes
-location_id
-2
-attributes
-location_id
I thought I could filter this by using
var get_locations = user_class_collection.filter(function(classes){
console.log(classes);
return classes.get(location_id)==location.id;
});
console.log(get_locations);
but that is returning an empty array, when I know the location_id is in the collection.
Any idea why this isn't working? I've also tried to grab classes.attributes.get, but it wasn't any better
In the first few responses, it was properly mentioned that I had to quote the get('location_id'). I've now done that, but unfortunately, I'm still getting an empty array. I thought that the filter would loop through the classes and I would get a console output for each class, but the console.log(classes) is only getting triggered once. Is that a hint? Or a red-herring?
you are trying to get a property from classes that is named as the value of the location_id parameter
you should instead make that a string (in fact you can choose how you make it a string, single or double quotes both work)
user_class_collection.filter(function(classes){
return classes.get('location_id') == location.id;
});
For filtering collection using backbone the best approach is to use a filtered function in your collection
var UserCollection = Backbone.Collection.extend ({
filtered : function ( id ) {
I suggest to use UnderScore filter which will return true for valid and false for invalid where true is what you are looking for. use this.models to get the current collection models use model.get( '' ) to get the element you want to check for
var results = _.filter( this.models, function ( model ) {
if ( model.get('location_id') == id )
return true ;
return false ;
});
Then use underscore map your results and transform it to JSON like
results = _.map( results, function( model ) { return model.toJSON() } );
Finally returning a new backbone collection with only results
return new Backbone.Collection( results ) ;
Optionally if you don't want to keep all the data in the collection but just the filtered one you should reset the collection and skip the above return like
this.reset( results ) ;
View call the filtered collection and the render the result
Try this:
user_class_collection.select(function(classes){
return classes.get("location_id")==location.id;
});