Can Atuf Kansu
Can Atuf Kansu

Reputation: 523

What is the correct way of using @scope directive?

I'm having trouble understanding how @scope directive works. When I add the directive to query definition and give the IsOwner: true Lighthouse adds it to the scope but the problem starts when I change it to IsOwner:false. Lighthouse still applies the scope into the query. Only time Lighthouse doesn't apply the scope when I remove IsOwner parameter from the query.

My query definition is like following;

listings(IsOwner: Boolean @scope(name:"IsOwner"), where: _ @whereConditions(columnsEnum: "ListingColumn"), orderBy: _ @orderBy(columnsEnum: "ListingColumn")) : [Listing!]! @paginate(maxCount: 50 defaultCount: 10)

And actual query is like below;

query ($min_lng:Float!, $min_lat:Float!, $max_lng:Float!, $max_lat:Float!, $first:Int, $page:Int, $withPaginatorInfo:Boolean!, $withListingImages:Boolean!, $withListingMeta:Boolean!, $withListingViews:Boolean!, $withListingActions:Boolean!, $withListingNotes:Boolean!, $withListingReminders:Boolean!, $withListingViewUser:Boolean = false, $conditions: ListingsWhereWhereConditions, $orderBy: [ListingsOrderByOrderByClause!]) {
listings(
    bbox: {
        min_lng: $min_lng
        min_lat: $min_lat
        max_lng: $max_lng
        max_lat: $max_lat
    }
    IsOwner: false
    where:  $conditions
    orderBy: $orderBy
    first: $first
    page: $page
) {
    data {
        ...listingFields
    }
    paginatorInfo @include(if: $withPaginatorInfo) {
        currentPage
        lastPage
    }
}

}

Model scope it like following;

    public function scopeIsOwner($query)
    {
        return $query->join('listing_user', 'listing_user.listing_id', '=', 'listings.id')->where('listing_user.user_id', Auth::user()->id);
    }

*** UPDATE ***

I figured it out after the comments, I changed the model scope to the following

public function scopeIsOwner($query, $isEnabled)
    {
        if ($isEnabled) {
            return $query->join('listing_user', 'listing_user.listing_id', '=', 'listings.id')->where('listing_user.user_id', Auth::user()->id);
        }

        return $query;
    }

I made minor changes on the schema like below,

listings(scopeIsOwner: Boolean @scope(name:"IsOwner"), bbox: BoundingBoxInput! @builder(method: "App\\GraphQL\\Builders\\BoundingBoxSearch@bbSearch"), where: _ @whereConditions(columnsEnum: "ListingColumn"), orderBy: _ @orderBy(columnsEnum: "ListingColumn")) : [Listing!]! @guard(with: ["api"]) @paginate(maxCount: 50 defaultCount: 10)

My final query and it's variable is like the following,

query ($min_lng:Float!, $min_lat:Float!, $max_lng:Float!, $max_lat:Float!, $first:Int, $page:Int, $withPaginatorInfo:Boolean!, $withListingImages:Boolean!, $withListingMeta:Boolean!, $withListingViews:Boolean!, $withListingActions:Boolean!, $withListingNotes:Boolean!, $withListingReminders:Boolean!, $withListingViewUser:Boolean = false, $scopeIsOwner:Boolean = false $conditions: ListingsWhereWhereConditions, $orderBy: [ListingsOrderByOrderByClause!]) {
    listings(
        bbox: {
            min_lng: $min_lng
            min_lat: $min_lat
            max_lng: $max_lng
            max_lat: $max_lat
        }
        scopeIsOwner: $scopeIsOwner
        where:  $conditions
        orderBy: $orderBy
        first: $first
        page: $page
    ) {
        data {
            ...listingFields
        }
        paginatorInfo @include(if: $withPaginatorInfo) {
            currentPage
            lastPage
        }
    }
}

Variables;

{
  "min_lng": 29.0401317,
  "min_lat": 41.0028473,
  "max_lng": 29.0308512,
  "max_lat": 40.9916271,
  "withPaginatorInfo" : true,
  "first": 10,
  "page": 1,
  "withListingImages": false,
  "withListingMeta": false,
  "withListingViews": false,
  "withListingActions": false,
  "withListingNotes": false,
  "withListingReminders": false,
  "withListingViewUser": false,
  "conditions": {"AND": [{"column": "PRICE", "operator": "LTE","value": "190"}]},
  "orderBy": [{ "column": "TENURE_ID", "order": "DESC" }],
  "scopeIsOwner": false
}

As you can understand when I give true to scopeIsOwner variable endpoint enables the scope and manipulate the query accordingliy.

Upvotes: 1

Views: 1695

Answers (2)

spawnia
spawnia

Reputation: 909

You are misunderstanding. See https://lighthouse-php.com/master/api-reference/directives.html#scope

The scope method will receive the client-given value of the argument as the second parameter.

Your scope should react to the argument the client passes.

Upvotes: 2

Bartłomiej Gajda
Bartłomiej Gajda

Reputation: 64

There is a bug in Lighthouse library. Scope is added when parameter exist without checking value. ScopeDirective class and handleBuilder method are quite simple

public function handleBuilder($builder, $value)
    {
        $scope = $this->directiveArgValue('name');

        try {
            return $builder->{$scope}($value);
        } catch (BadMethodCallException $exception) {
            throw new DefinitionException(
                $exception->getMessage()." in {$this->name()} directive on {$this->nodeName()} argument.",
                $exception->getCode(),
                $exception->getPrevious()
            );
        }
    }

I think $value contains true or false and this variable should not be injected to scope here:

$builder->{$scope}($value);

Instead, should be something like:

if ($value == true) {
    $builder->{$scope}();
}

Upvotes: 0

Related Questions