Skip to content

Conversation

Simperfit
Copy link
Contributor

@Simperfit Simperfit commented May 7, 2016

Q A
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #530
License MIT

This is WIP

Edit : This is ok for review

  • Finish the test behat
  • Add more test for composite
  • Modify the behaviour of ItemDataProvider to test the composite identifiers and to make uuid work

@Simperfit Simperfit force-pushed the fix-uuid-530 branch 5 times, most recently from 55aa7d1 to 67e1333 Compare May 7, 2016 17:17
@Simperfit
Copy link
Contributor Author

ping @dunglas.
This PR is ready for review ( @theofidry @polc).

@Simperfit Simperfit changed the title [WIP] #530 ~ Add behat test and change behavior of ItemDataProvider for uuid #530 ~ Add behat test and change behavior of ItemDataProvider for uuid May 7, 2016
@createSchema
@dropSchema
Scenario: Get collection with composite identifiers
Scenario: Get a compisite item with composite identifiers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

$placeholder = 'id_'.$propertyName;
$whereExpr[$i] = $queryBuilder->expr()->eq('o.'.$propertyName, ':'.$placeholder);

if ($i <= 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could use an iterator here instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ill look at it

Copy link
Contributor Author

@Simperfit Simperfit May 7, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 foreach ($identifiers as $propertyName => $value) {
            $placeholder = 'id_'.$propertyName;
            $whereExpr[] = $queryBuilder->expr()->eq('o.'.$propertyName, ':'.$placeholder);
            $whereExprObj = new \ArrayObject($whereExpr);
            var_dump($whereExprObj);
            $whereIterator = $whereExprObj->getIterator();
            var_dump($whereIterator->key());
            if ($whereIterator->key() <= 0) {
                $queryBuilder
                    ->where($whereIterator->current());
            } else {
                $queryBuilder
                    ->andWhere($whereIterator->current());
            }
            $queryBuilder->setParameter($placeholder, $value);

            $whereIterator->next();
        }

I can't make it working since the array is populated at the same time that I test it keys.
Do you see something wrong in what i've tried to achieve ?

Copy link
Contributor

@theofidry theofidry May 7, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of an interator on $identifiers rather

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've missunderstand that comment line ;(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no worries :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this ?

@Simperfit Simperfit force-pushed the fix-uuid-530 branch 4 times, most recently from 1996b64 to f67ceca Compare May 7, 2016 19:48
->setParameter($placeholder, $value);
++$i;
$identifiersObjIterator->next();
}
Copy link
Contributor

@theofidry theofidry May 7, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of the iterator is to get rid of $i. You can easily have something more readable by putting that into a private function:

$this->processIdentifiers($identifiers, $queryBuilder);

private function processIdentifiers(array $identifiers, QueryBuilder $queryBuilder)
{
    if (0 === count($identifiers)) {
        return;
    }
    $iterator = (new \ArrayObject($identifiers))->getIterator();

    $queryBuilder->where(
        $queryBuilder->expr()->eq(
            'o.'.$identifiersObjIterator->key(),
            ':id_'.$identifiersObjIterator->key()
        )
    );
    $queryBuilder->setParameter($'id_'.$identifiersObjIterator->key(), $identifiersObjIterator->current());
    $iterator->next();

    while($iterator->valid()) {
        $queryBuilder->andWhere(
            $queryBuilder->expr()->eq(
                'o.'.$identifiersObjIterator->key(),
                ':id_'.$identifiersObjIterator->key()
            )
        );
        $queryBuilder->setParameter('id_'.$identifiersObjIterator->key(), $identifiersObjIterator->current());
        $iterator->next();
    }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but to be fair, you could have another version where you check just if you're on the first property or not:

private function processIdentifiers(array $identifiers, QueryBuilder $queryBuilder)
{
    if (0 === count($identifiers)) {
        return;
    }

    $firstIdentifier = reset($identifiers);
    foreach($identifiers as $identifier => $value) {
        $placeholder = ':id_'.$identifier;
        $expression = $queryBuilder->expr()->eq(
            'o.'.$identifier,
            ':'.$placeholder
        );

        if ($firstIdentifier === $identifier) {
            $queryBuilder->where($expression);
        } else {
            $queryBuilder->andWhere($expression);
        }

        $queryBuilder->setParameter($placeholder, $value);
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will prefer the iterator version, it's readable and fun to use ;).

WDYT ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a fun case to play with the iterator which is why I mentioned it, but I must admit I find the second version more readable and accessible.

@Simperfit Simperfit force-pushed the fix-uuid-530 branch 3 times, most recently from b0a9590 to 6ed35e7 Compare May 7, 2016 20:27
@Simperfit
Copy link
Contributor Author

Thanks for the help @theofidry !

@polc
Copy link
Contributor

polc commented May 8, 2016

I didn't looked into the code but this patch is working on my project 👍

}

$identifierValues = explode('-', $id);
$identifierValues = (array) $id;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casting to an array is useless IIRC.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use it as an array later in the code. Do we have to cast it in a other way ?
L130

 $firstIdentifier = reset($identifiers);
 foreach ($identifiers as $identifier => $value) {

Copy link
Contributor

@teohhanhui teohhanhui May 9, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be happy if this whole identifiers business can be moved into a separate method:

$identifiers = $this->normalizeIdentifiers($id);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the same class ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a first step, yes. We could certainly extract it out later if that makes sense...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok like this ?

@Simperfit Simperfit force-pushed the fix-uuid-530 branch 4 times, most recently from 9812b8a to 69e9988 Compare May 10, 2016 06:22
* @param array $identifiers
* @param QueryBuilder $queryBuilder
*
* Populate the query with where when needed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not valid PHPDoc. It assume you forgot to clean up here.

Anyway, I suggest to rephrase it like this:

Add WHERE conditions to the query for one or more identifiers (simple or composite).

@Simperfit Simperfit force-pushed the fix-uuid-530 branch 2 times, most recently from ddf2461 to e2ab7cc Compare May 11, 2016 20:10

if ($propertyMetadata->isIdentifier()) {
$identifierValues[] = $this->propertyAccessor->getValue($item, $propertyName);
$identifierValuesComposite[] = $propertyName.'='.$this->propertyAccessor->getValue($item, $propertyName);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THIS, feels like a hack.

Copy link
Contributor

@teohhanhui teohhanhui May 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just change the above line to:

$identifiers[$propertyName] = $this->propertyAccessor->getValue($item, $propertyName);

Then do this after the loop:

if (1 === count($identifiers)) {
    $identifiers = array_map(function ($identifierValue) {
        return rawurlencode($identifierValue);
    }, $identifiers);
} else {
    $identifiers = array_map(function ($identifierName, $identifierValue) {
        return sprintf('%s=%s', $identifierName, rawurlencode($identifierValue));
    }, array_keys($identifiers), $identifiers);
}

And finally:

return $this->router->generate($routeName, ['id' => implode(',', $identifiers)], $referenceType);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the help ! Ill modify that asap

@Simperfit Simperfit force-pushed the fix-uuid-530 branch 2 times, most recently from ec18af3 to aabd844 Compare May 12, 2016 12:00
public function getId()
{
return sprintf('%s-%s', $this->compositeItem->getId(), $this->compositeLabel->getId());
return sprintf('%s;%s', $this->compositeItem->getId(), $this->compositeLabel->getId());
Copy link
Contributor

@teohhanhui teohhanhui May 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this method? I don't see it being used anywhere...

Copy link
Member

@soyuka soyuka May 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake, I think this is some leftovers from my tests with api-platform 1.x ref #282 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked myself too, but :
If we remove that :

{
                  "@id": "\/composite_relations\/compositeItem=1;compositeLabel=1",
                  "@type": "CompositeRelation",
                  "id": null,
                  "value": "somefoobardummy"
              }

Where id is null, but when this exist, the ID is correct :
"id": "1;1"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A separate id property? Where does it come from when there's no getId method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand, there is one, we are talking about that method no ?

 public function getId() {
...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, is it still a problem if we remove this method from CompositeRelation (and from the related tests too, of course)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it's useless

@dunglas dunglas merged commit b3cf3b7 into api-platform:master May 14, 2016
@dunglas
Copy link
Member

dunglas commented May 14, 2016

Thank you @Simperfit

magarzon pushed a commit to magarzon/core that referenced this pull request Feb 12, 2017
api-platform#530 ~ Add behat test and change behavior of ItemDataProvider for uuid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants