I use webstorm v 10.0.4. I want to use JSDoc in webstorm to verify if there are some mistakes in the objects properties used. I expect the following example showing warning but nothing happen.
In the setting panel, in Editor->Inspections, in Javascript->General, 3 parameters appears when filtered by "jsdoc":
JsDoc comment matches function signature
Potentially invalid constructor usage
Validate JsDoc /ASDoc
The 3 of them are selected to show warnings
here my example which do not show any warning:
/**
*
* #typedef {Object} cleanJRef
*
* #property {string} rRefName
* #property {string} rActiveId
* #property {string} rActiveName
* #property {string} rDbId
* #property {string} rDbName
* #property {Object} rActiveElt
*/
//TODO: why this test do not show a warning or error in webstorm?
/** #type {cleanJRef} */
var testCleanJRef = {
rRefName: 1, //should have a warning here
rActiveId: "0",
rActiveName: "Name",
rDbId: "0",
rDbName: "nom",
rActiveElt: "new Object()", //should have a warning here
incorrectProp: "false" //should have a warning here
};
Type checking is only done when using assignments like testCleanJRef.rRefName = 1;. Please vote for WEB-19342 to be notified on any progress with it
There is no warning for each wrong line but a warning saying:
"Initializer type {rRefName: number, rActiveId: string..., incorrectProp: string} is not assignable to varialbe type cleanJRef."
I don't know why I did not see it at first...
Related
So i have an Entity with #Assert/Regex
/**
* #var string
*
* #ORM\Column(name="firstname", type="string", length=30, nullable=false, options={"comment"="input#text&[A-Za-z \-\'àâäçéèêëîïôöùûüÿæœÀÂÄÇÉÈÊËÎÏÔÖÙÛÜŸÆŒ]{2,30}#Prénom"})
* #Assert\NotBlank (
* message="Le champs [prénom] ne peut être vide",
* groups={"registration"}
* )
* #Assert\Regex (
* pattern="/^[A-Za-z \-\'àâäçéèêëîïôöùûüÿæœÀÂÄÇÉÈÊËÎÏÔÖÙÛÜŸÆŒ]{2,30}$/",
* message="Champs prénom : La saisie est invalide (min: 2, max: 30)")
*/
private $firstname;
/**
* #var string
*
* #ORM\Column(name="lastname", type="string", length=30, nullable=false, options={"comment"="input#text&[A-Za-z \-\'àâäçéèêëîïôöùûüÿæœÀÂÄÇÉÈÊËÎÏÔÖÙÛÜŸÆŒ]{2,30}#Nom"})
* #Assert\NotBlank (
* message="Le champs [nom] ne peut être vide",
* groups={"registration"}
* )
* #Assert\Regex (
* pattern="/^[A-Za-z \-\'àâäçéèêëîïôöùûüÿæœÀÂÄÇÉÈÊËÎÏÔÖÙÛÜŸÆŒ]{2,30}$/",
* message="Champs nom : La saisie est invalide (min: 2, max: 30)")
*/
private $lastname;
And i have my controller like so (I purposely removed most of my code to keep it lisible)
public function register(ValidatorInterface $validator, EntityManagerInterface $emi): Response
{
$newUsers = new Users();
// Setting the values
$newUsers
->setFirstname($request->get('firstname'))
->setLastname($request->get('lastname'));
$errorsUsers = $validator->validate($newUsers, null, ['registration']);
foreach ($errorsUsers as $v){
$msgErrors .= "\n- " . $v->getMessage() . ".";
}
}
Before everything worked perfectly. And now the Assert\NotBlank is still working but the Assert\Regex is not. It's like, it doesn't even compare it.
I tried :
php bin/console debug:validator 'App\Entity\Users' (all seems fine)
composer dump-autoload (nothing change)
Put instead in my regex simple parttern like "/\d/" (even that when i type 'Toto' it doesn't trigger and return a violation)
I don't know why it's not working anymore and thats why i hate symfony for this cause it doesn't even give an error or message to start with.
If someone has encountered this problem and has a solution to give, please let me know.
Thanks in advance.
The accepted answer is not fully correct. If you don't specify groups it means that it apply for everything, which it is TRUE! BUT, you have to pass the "Default" (it really is the name of symfony default validation group). Otherwise, if you only use your custom validation group, and leave the "Default" out of it, then it will ignore the asserts with no custom validation group specified.
Ok so the problem was the fact that i didn't put the groups in the regex too.
so for each Assert that you add on a var, you need to specify the groups.
I didn't think of it, because in the doc it says that if you don't specify groups it means that it apply for everything. Obviously it is not.
Thanks doc.
Yep, the title suggests: Doctrine is looking for a fieldname that's not there. That's both true and not true at the same time, though I cannot figure out how to fix it.
The full error:
File: D:\path\to\project\vendor\doctrine\dbal\lib\Doctrine\DBAL\Driver\AbstractMySQLDriver.php:71
Message: An exception occurred while executing 'SELECT DISTINCT id_2
FROM (SELECT p0_.name AS name_0, p0_.code AS code_1, p0_.id AS id_2
FROM product_statuses p0_) dctrn_result ORDER BY p0_.language_id ASC, name_0 ASC LIMIT 25
OFFSET 0':
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'p0_.language_id' in 'order clause'
The query the error is caused by (from error above):
SELECT DISTINCT id_2
FROM (
SELECT p0_.name AS name_0, p0_.code AS code_1, p0_.id AS id_2
FROM product_statuses p0_
) dctrn_result
ORDER BY p0_.language_id ASC, name_0 ASC
LIMIT 25 OFFSET 0
Clearly, that query is not going to work. The ORDER BY should be in the sub-query, or else it should replace p0_ in the ORDER BY with dctrn_result and also get the language_id column in the sub-query to be returned.
The query is build using the QueryBuilder in the indexAction of a Controller in Zend Framework. All is very normal and the same function works perfectly fine when using a the addOrderBy() function for a single ORDER BY statement. In this instance I wish to use 2, first by language, then by name. But the above happens.
If someone knows a full solution to this (or maybe it's a bug?), that would be nice. Else a hint in the right direction to help me solve this issue would be greatly appreciated.
Below additional information - Entity and indexAction()
ProductStatus.php - Entity - Note the presence of language_id column
/**
* #ORM\Table(name="product_statuses")
* #ORM\Entity(repositoryClass="Hzw\Product\Repository\ProductStatusRepository")
*/
class ProductStatus extends AbstractEntity
{
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* #var string
* #ORM\Column(name="code", type="string", length=255, nullable=false)
*/
protected $code;
/**
* #var Language
* #ORM\ManyToOne(targetEntity="Hzw\Country\Entity\Language")
* #ORM\JoinColumn(name="language_id", referencedColumnName="id")
*/
protected $language;
/**
* #var ArrayCollection|Product[]
* #ORM\OneToMany(targetEntity="Hzw\Product\Entity\Product", mappedBy="status")
*/
protected $products;
[Getters/Setters]
}
IndexAction - Removed parts not directly related to QueryBuilder. Added in comments showing params as they are.
/** #var QueryBuilder $qb */
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select($asParam) // 'pro'
->from($emEntity, $asParam); // Hzw\Product\Entity\ProductStatus, 'pro'
if (count($queryParams) > 0 && !is_null($query)) {
// [...] creates WHERE statement, unused in this instance
}
if (isset($orderBy)) {
if (is_array($orderBy)) {
// !!! This else is executed !!! <-----
if (is_array($orderDirection)) { // 'ASC'
// [...] other code
} else {
// $orderBy = ['language', 'name'], $orderDirection = 'ASC'
foreach ($orderBy as $orderParam) {
$qb->addOrderBy($asParam . '.' . $orderParam, $orderDirection);
}
}
} else {
// This works fine. A single $orderBy with a single $orderDirection
$qb->addOrderBy($asParam . '.' . $orderBy, $orderDirection);
}
}
================================================
UPDATE: I found the problem
The above issue is not caused by incorrect mapping or a possible bug. It's that the QueryBuilder does not automatically handle associations between entities when creating queries.
My expectation was that when an entity, such as ProductStatus above, contains the id's of the relation (i.e. language_id column), that it would be possible to use those properties in the QueryBuilder without issues.
Please see my own answer below how I fixed my functionality to be able to have a default handling of a single level of nesting (i.e. ProducStatus#language == Language, be able to use language.name as ORDER BY identifier).
Ok, after more searching around and digging into how and where this goes wrong, I found out that Doctrine does not handle relation type properties of entities during the generation of queries; or maybe does not default to using say, the primary key of an entity if nothing is specified.
In the use case of my question above, the language property is of a #ORM\ManyToOne association to the Language entity.
My use case calls for the ability to handle at lease one level of relations for default actions. So after I realized that this is not handled automatically (or with modifications such as language.id or language.name as identifiers) I decided to write a little function for it.
/**
* Adds order by parameters to QueryBuilder.
*
* Supports single level nesting of associations. For example:
*
* Entity Product
* product#name
* product#language.name
*
* Language being associated entity, but must be ordered by name.
*
* #param QueryBuilder $qb
* #param string $tableKey - short alias (e.g. 'tab' with 'table AS tab') used for the starting table
* #param string|array $orderBy - string for single orderBy, array for multiple
* #param string|array $orderDirection - string for single orderDirection (ASC default), array for multiple. Must be same count as $orderBy.
*/
public function createOrderBy(QueryBuilder $qb, $tableKey, $orderBy, $orderDirection = 'ASC')
{
if (!is_array($orderBy)) {
$orderBy = [$orderBy];
}
if (!is_array($orderDirection)) {
$orderDirection = [$orderDirection];
}
// $orderDirection is an array. We check if it's of equal length with $orderBy, else throw an error.
if (count($orderBy) !== count($orderDirection)) {
throw new \InvalidArgumentException(
$this->getTranslator()->translate(
'If you specify both OrderBy and OrderDirection as arrays, they should be of equal length.'
)
);
}
$queryKeys = [$tableKey];
foreach ($orderBy as $key => $orderParam) {
if (strpos($orderParam, '.')) {
if (substr_count($orderParam, '.') === 1) {
list($entity, $property) = explode('.', $orderParam);
$shortName = strtolower(substr($entity, 0, 3)); // Might not be unique...
$shortKey = $shortName . '_' . (count($queryKeys) + 1); // Now it's unique, use $shortKey when continuing
$queryKeys[] = $shortKey;
$shortName = strtolower(substr($entity, 0, 3));
$qb->join($tableKey . '.' . $entity, $shortName, Join::WITH);
$qb->addOrderBy($shortName . '.' . $property, $orderDirection[$key]);
} else {
throw new \InvalidArgumentException(
$this->getTranslator()->translate(
'Only single join statements are supported. Please write a custom function for deeper nesting.'
)
);
}
} else {
$qb->addOrderBy($tableKey . '.' . $orderParam, $orderDirection[$key]);
}
}
}
It by no means supports everything the QueryBuilder offers and is definitely not a final solution. But it gives a starting point and solid "default functionality" for an abstract function.
I was recently trying to use the cfscript version of cfcomponent along with JavaDoc notation and getting error:
The system has attempted to use an undefined value, which usually
indicates a programming error, either in your code or some system code.
Null Pointers are another name for undefined values.
From CF docs:
/**
* custom metadata for a cfc defined using annotation as well as key-value pairs
* #cfcMetadata1 "cfc metadata1"
*/
component cfcMetadata2 = "cfc metadata2"
{
/**
* custom metadata for a property defined using annotation as well as key-value pairs
* #propMetadata1 "property metadata1"
*/
property type="numeric" name="age" default="10" propMetadata2="property metadata2";
/**
* custom metadata for a function/argument using both annotation and key-value pairs
* #arg1.argmdata1 "arg metadata1"
* output true
* #fnMetadata1 "function metadata1"
*/
public string function foo(required numeric arg1=20 argmdata2="arg metadata2") fnMetadata2="function metadata2"
{
writedump(getmetadata(this));
return arg1;
}
}
My Code:
/**
* #displayName Test
* #output false
*
* #since 2016-10-25
* #version 1.0
*/
component {
/**
* I am a test function.
*
* #limitFrom.required false
* #limitFrom.default 0
*
* #limitBy.required false
* #limitBy.default 0
*
* #returnFormat "json"
*
* #since 2016-10-25
* #version 1.0
*/
remote query function test(
numeric limitFrom,
numeric limitBy
) {
return queryNew("");
}
}
This is only happening when I am trying to assign default value to the arguments using the JavaDoc notation i.e.,
#limitFrom.default 0
#limitBy.default 0
Removing these and everything is fine. Not sure why this is happening?
I know you specifically asked about JavaDoc notation, but I'm not a fan, and it's possible that you haven't seen any alternative. I prefer this syntax.
component
displayName="test"
output="false"
hint="blah blah description..."
{
// beware of `default`--it doesn't do what you might think.
// it's ignored unless you use ORM
property type="numeric" name="age" default="10"
hint="blah blah description..."
propMetadata2="property metadata2";
remote query function test(
numeric limitFrom=0 hint="blah blah description...",
numeric limitBy=0 hint="blah blah description..."
)
hint="I am a test function"
{
return queryNew("");
}
}
I have a data feed that has duplicated content (no idea why, it's an external feed), however we need to insert all items with a constraint on the title and type, i.e.
These can exist:
Name_A, Type_A
Name_A, Type_B
But only one of these should exist:
Name_A, Type_A
Name_A, Type_A
Here's the Entity code I'm using:
/**
* Restauration
*
* #ORM\Table(name="restauration", uniqueConstraints={#ORM\UniqueConstraint(name="name_unique", columns={"name_1", "restauration_type"})})
* #ORM\Entity(repositoryClass="iMotionTools\Repository\RestaurationRepository")
*/
class Restauration
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name_1", type="string", length=128, nullable=true)
*/
private $name1;
/**
* #var string
*
* #ORM\ManyToOne(targetEntity="RestaurationType", cascade={"persist"})
* #ORM\JoinColumn(name="restauration_type", referencedColumnName="id")
*/
private $type;
}
But I get this error when parsing and inserting the data:
SQLSTATE[23000]: Integrity constraint violation: 19 columns name_1, restauration_type are not unique:91:C:\coding\currate\vendor\doctrine\dbal\lib\Doctrine\DBAL\DBALException.php
I'm wondering whether the easy way is to just ignore the thrown exception? Looks like it's a driverExceptionDuringQuery that gets thrown during my call to $em->persist(); but I'm not sure how I would ignore if the call contains the above error?
If you want to ignore that, stop using constraint integrity.
{#ORM\UniqueConstraint(name="name_unique", columns={"name_1" //etc...
Your data has name_1 not unique this is why you have this error, integrity constraint check this, you can't ignore that, without remove the unique constraint parameters.
Edit :
You have to then, before persist data, check with your actual data in the table, if there is a duplicate entry for both name_1 AND Type, and do not persist them.
for check both you can use :
#UniqueEntity({"name", "type"})
found here :
validation multiple constraint columns
Even if it's for SF2, it's the same concept
I've removed the UniqueConstraint attribute from the table and added a function to check the objects list (which later get $entity->persist()-ed), using an array so that I can easily use it for different entity types, and it seems to work well now.
$key = $hashList ? '' : $page['id'];
foreach ($hashList as $method) {
$val = $object->{$method}();
if(is_object($val)) {
$val = $val->getId();
}
$key .= $val;
}
$key = md5($key);
$objects[$key] = $object;
Where $hashList = array('getName', 'getType') - and getType returns an object (since it's another entity), but which always has the getId() function... probably not the best solution but it works for my situation...
I have the following code, which retrieves the page slugs from the database which are needed to then create a related sub page:
$builder->add('subtocontentoptions', 'entity', array(
'class' => 'ShoutAdminBundle:Content',
'property' => 'slug',
'query_builder' => function($repository) {
return $repository->createQueryBuilder('p')
->where('p.mainpage = :main')
->setParameter('main', '1')
->orderBy('p.created', 'ASC');
}
));
The code works, as it displays a drop down menu of all the parent pages I have. However, when I go to save the data to the database, I am given the following error:
ErrorException: Catchable Fatal Error: Object of class
Shout\AdminBundle\Entity\Content could not be converted to string in
C:\wamp\www\vendor\doctrine-dbal\lib\Doctrine\DBAL\Statement.php line
131
I have checked the contents of the Content entity file, and here is the variable being declared:
/**
* #var integer $subtocontentoptions
*
* #ORM\Column(name="SubToContentOptions", type="integer", nullable=false)
*/
private $subtocontentoptions;
And lower down the Content entity file:
/**
* Set subtocontentoptions
*
* #param integer $subtocontentoptions
*/
public function setSubtocontentoptions($subtocontentoptions)
{
$this->subtocontentoptions = $subtocontentoptions;
}
/**
* Get subtocontentoptions
*
* #return integer
*/
public function getSubtocontentoptions()
{
return $this->subtocontentoptions;
}
The rest of the code does work, once this drop down has been taken out. I'm not sure why the drop down is causing this error?
Thanks
Was having the same issue with a sf2/doctrine2 project, implementing the __toString method resolved this issue for me :
public function __toString()
{
return strval($this->id);
}