Is there a phpdoc-compliant way* of expressing the various returned values in a PHPUnit dataProvider?
For example:
return array(
array(false, 17, array(1,2)),
array(true, 19, array(1,2)),
);
I would like to write something more detailed than #return array, that expresses that the first value passed to the test method is a bool, the second is an integer, third is an array (and also what each of these values represent).
* If there's no compliant way, does anyone have tips on how to document in a clear manner?
The only further specification for arrays is what they contain (if always the same type):
/**
* #return array[]
*/
function() {
// ...
}
This annotation expresses the function will return an array of arrays, you can find a further discussion in this question:
PHPDoc type hinting for array of objects?
Note: Not every IDE will be able to interpret it
To a possible clear manner: In my opinion, you can always use code blocks in your comments to explain some of your code:
/**
* returns array with following structure:
* <code>
* array(
* array(
* (bool), (int), (array)
* )
* )
* </code>
*
* #return array[]
*/
Or similar explanation. I'm sure there are plenty ways to give other developers a hint about what to expect. In the end it just needs to be understandable to a human if it is not included in the usual annotations.
Related
Trying to validate if one field is not empty (length > 0) then the length of the field being validated must be a certain length (2 characters). It seems like an "Assert\Expression" might work in this situation but I am having trouble trying to find the length of the properties. It seems like you cannot call php functions within the Expression. The expression documentation mentions functions but maybe I do not understand it... Do I need to register my own function that simply return a strlen(). If so how do you register your own functions? Can someone explain if there is a way to do this, or maybe there is a better way than using Expression that I am overlooking...
/**
* #var string
*
* #ORM\Column(name="plate", type="string", length=10)
*/
private $plate;
/**
* #var string
*
* #ORM\Column(name="state", type="string", length=2)
* #Assert\Expression(
* "strlen(this.getPlate()) == 0 or (strlen(this.getPlate()) > 0 and strlen(value) == 2)",
* message="Must be 2 characters"
* )
*/
private $state;
In the above case I get an error The function "strlen" does not exist around position 1
Looks like you will need to register your own function. Have a look at the docs: https://symfony.com/doc/current/components/expression_language/extending.html#registering-functions
There is an example on lowercase, strlen should be very similar.
EDIT:
You can also use a callback validator.
/**
* #Assert\Callback()
*/
public function validateState(ExecutionContextInterface $context)
{
if (!empty($this->plate) && mb_strlen($this->state) !== 2) {
$context->buildViolation('State must be 2 characters long')
->atPath('state')
->addViolation();
}
}
But if you are planning to using this kind of validation in multiple places, you can write and register your own validator.
If I have a variable of a type ArrayCollection how do I check if a key of a specific name exists in the collection including nesting. And if it does how do I get and change that value?
I guess you are talking about Doctrines ArrayCollection \Doctrine\Common\Collections\ArrayCollection.
It does implement phps native ArrayAccess interface, so have a look at the docs. Just check like:
use Doctrine\Common\Collections\ArrayCollection;
$myCollection = new ArrayCollection(array('testKey' => 'testVal'));
var_dump(isset($myCollection['testKey']));
It does also implement its own method from the Collection interface.
/**
* Checks whether the collection contains an element with the specified key/index.
*
* #param string|integer $key The key/index to check for.
*
* #return boolean TRUE if the collection contains an element with the specified key/index,
* FALSE otherwise.
*/
public function containsKey($key);
For nested objects there is no build in method, you have to traverse the collection yourself like you would do with a normal array.
The way that I found was to use the toArray() method in the ArrayCollection object and then use the array_search function:
$newArray = $arrayCollectionObject->toArray();
$keyThatIneed = array_search($value, $newArray);
I find it somewhat annoying to have to constantly use #var on getUser. It seems sloppy.
So I was thinking about starting to use this instead
<?php
// in the controller
$user = Customer::isCustomer($this->getUser());
// in the entity
/**
* #param Customer $user
*
* #return Customer
*/
public static function isCustomer(Customer $user)
{
return $user;
}
Is this a good idea? Bad idea? Horrible idea?
A type hint is the better option in this case.
Why would you write more code by adding checks manually rather than adding a simple type hint to your param.
Your four lines of codes representing two conditions give exactly the same result as:
/**
* #param Customer|null $user
*
* #return Customer|null
*/
public static function isCustomer(Customer $user = null)
{
// If $user is null, it works
// If $user is a Customer instance, it works
// If it's other, an exception is thrown
return $user;
}
Type hinting optimises and give more readability to a code.
It's a convention in symfony2, php and more.
It's commonly used as a constraint (or contract) with you and your method.
Also, it's the only alternative for an interface or an abstract class to add requirement to a parameter, because they don't have a body, and so cannot write conditions.
Update
In SensioLabs Insight, Object type hinting represents a warning using the following message :
The parameter user, which is an object, should be typehinted.
Because the verb should is used, I consider it's not a mandatory requirement, just a very good practice in case of it doesn't cause any problem.
Also, you can use the example you given without making your code horrible.
I have to know what are the codes(ISO codes) of the languages in
Intl::getLanguageBundle()->getLanguageNames($this->name);
Anyone know how to do that?
Update
I discover that the codes are in
"alpha-2 code" and exist a list in the site http://www.nationsonline.org/oneworld/language_code.htm
but I what to see the list of the Intl::getLanguageBundle() to see if it has any different codes
Thanks in advance for any help
From the LanguageBundleInterface class, here's the relevant docblock:
/**
* Returns the names of all known languages.
*
* #param string $displayLocale Optional. The locale to return the names in.
* Defaults to {#link \Locale::getDefault()}.
*
* #return string[] A list of language names indexed by language codes.
*/
public function getLanguageNames($displayLocale = null);
So you just need to use the result like this:
$languages = Intl::getLanguageBundle()->getLanguageNames($this->name);
foreach ($languages as $code => $name) {
/*...*/
}
I need to implement an OR operator between some filters in a Drupal View.
By default, Drupal AND's every filter together.
By using
hook_views_query_alter(&$view, &$query)
I can access the query ( var $query ) , and I can change either :
$query->where[0]['type']
to 'OR', or
$query->group_operator
to 'OR'
The problem is however, that I do not need OR's everywhere. I've tried changing both of them to OR seperately, and it doesn't yield the desired result.
It seems changing those values, puts OR's everywhere, while I need => ( filter 1 AND filter 2 ) OR ( filter 3 ), so just 1 OR.
I could just check the Query of the View, copy it, modify it, and run it through db_query, but that's just dirty ..
Any suggestions ?
Thx in advance.
If you are using Views 3 / Drupal 7 and looking for the answer to this question, it is baked right into Views. Where it says "add" next to filters, click the dropdown, then click "and/or; rearrange". It should be obvious from there.
Unfortunately this is still a missing feature in Views2. It has long been asked for and was promised a while ago, but seems to be a tricky piece of work and is now scheduled for Views3.
In the meantime you could try the Views Or module mentioned in that thread. As of today, it is still in dev status, but seems to be actively maintained and the issue queue does not look to bad, so you might want to give it a try.
if you want do it with view_query_alter hook, you should use $query->add_where() where you can specify if it's AND or OR. From views/include/query.inc
/**
* Add a simple WHERE clause to the query. The caller is responsible for
* ensuring that all fields are fully qualified (TABLE.FIELD) and that
* the table already exists in the query.
*
* #param $group
* The WHERE group to add these to; groups are used to create AND/OR
* sections. Groups cannot be nested. Use 0 as the default group.
* If the group does not yet exist it will be created as an AND group.
* #param $clause
* The actual clause to add. When adding a where clause it is important
* that all tables are addressed by the alias provided by add_table or
* ensure_table and that all fields are addressed by their alias wehn
* possible. Please use %d and %s for arguments.
* #param ...
* A number of arguments as used in db_query(). May be many args or one
* array full of args.
*/
function add_where($group, $clause)
I added it by concatenating the string.
It is relatively specific to the implementation - people would need to play with field to match for OR - node.title in the following code and the field to match it with - node_revisions.body in this case.
Extra piece of code to make sure that node_revisions.body is in the query.
/**
* Implementation of hook_views_api().
*/
function eventsor_views_api() { // your module name into hook_views_api
return array(
'api' => 2,
// might not need the line below, but in any case, the last arg is the name of your module
'path' => drupal_get_path('module', 'eventsor'),
);
}
/**
*
* #param string $form
* #param type $form_state
* #param type $form_id
*/
function eventsor_views_query_alter(&$view, &$query) {
switch ($view->name) {
case 'Events':
_eventsor_composite_filter($query);
break;
}
}
/**
* Add to the where clause.
* #param type $query
*/
function _eventsor_composite_filter(&$query) {
// If we see "UPPER(node.title) LIKE UPPER('%%%s%%')" - then add and to it.
if (isset($query->where)) {
$where_count = 0;
foreach ($query->where as $where) {
$clause_count = 0;
if (isset($where['clauses'])) {
foreach ($where['clauses'] as $clause) {
$search_where_clause = "UPPER(node.title) LIKE UPPER('%%%s%%')";
// node_data_field_long_description.field_long_description_value
$desirable_where_clause = "UPPER(CONCAT_WS(' ', node.title, node_revisions.body)) LIKE UPPER('%%%s%%')";
if ($clause == $search_where_clause) {
// $query->add_where('or', 'revisions.body = %s'); - outside of what we are looking for
$query->where[$where_count]['clauses'][$clause_count] = $desirable_where_clause;
// Add the field to the view, just in case.
if (!isset($query->fields['node_revisions_body'])) {
$query->fields['node_revisions_body'] = array(
'field' => 'body',
'table' => 'node_revisions',
'alias' => 'node_revisions_body'
);
}
}
$clause_count++;
}
}
$where_count++;
}
}
}