0

I have five tables: requesters, document types, protocols, flows and documents.

Relationships

  • Requester has many document types.
  • Requester has many protocols.
  • Protocol has many flows.
  • Flow has many documents.
  • Document type has many documents.

Problem

Select all protocols that have the first flow (let's say sequence = 1) with documents having all document types for protocol requester.

In other words, select the protocols that doesn't have pendencies, this means protocols with documents inside first flow having all required document types for protocol requester.

Solution

I ended up with a solution that actually doesn't work because I can't access requester_id value inside protocols whereHas Closure:

// All document types id's group by requester id's.
$documentTypesByRequester = DocumentType::all()
  ->groupBy('requester_id')
  ->map(function ($documentTypes, $requesterId) {
      return $documentTypes->pluck('id')
             ->toArray();
  })->toArray();
// Defined statically to reduce the complexity of question.
// $documentTypesByRequester = [
//    1 => [1, 2, 3],
//    2 => [4, 5]
// ];
// Here I have to select all protocols that have flows with
// documents having all document types of protocol requester.
$protocols = Protocol::whereHas('flows', function ($flows) use ($documentTypesByRequester) {
    // 
    // *---------------------------------------
    // * THIS DOESN'T WORK BUT IS WHAT I NEED!
    // *---------------------------------------
    // 
    // Access the requester id for current protocol.
    $requesterId = $flows->first()
        ->protocol
        ->requester_id;
    $documentTypesId = $documentTypesByRequester[$requesterId];

    return $flows->where('sequence', 1)
        ->whereHas('documents', function ($documents) use ($documentTypesId) {
            return $documents->whereIn('document_type_id', $documentTypesId);
        }, '=', count($documentTypesId));
})->get();

There is some way to access values of model inside this whereHas Closure or exists another alternative to help me solve this query?

5
  • Hey, could you also share the code where you don't set documentTypesByRequester statically? I want to give this query a try, but with static data it's a bit tricky and I might unnecessarily over-complicate stuff. Commented Sep 18, 2018 at 16:05
  • @AndriusRimkus no secret. Updated question. Commented Sep 18, 2018 at 17:10
  • Can you post your migrations and relationships? Commented Sep 18, 2018 at 21:24
  • Can a flow have multiple documents of the same type (per requester)? Commented Sep 18, 2018 at 22:42
  • @JonasStaudenmeir yes! Commented Sep 19, 2018 at 3:28

1 Answer 1

1

Try this:

$documentTypes = DocumentType::whereColumn('requester_id', 'protocol.requester_id');
$protocols = Protocol::whereHas('flows', function ($query) use ($documentTypes) {
    $query->where('sequence', 1)
        ->whereHas('documents', function ($query) use ($documentTypes) {
            $query->select(DB::raw('count(distinct document_type_id)'))
                ->whereIn('document_type_id', (clone $documentTypes)->select('id'));
        }, '=', DB::raw('('.(clone $documentTypes)->selectRaw('count(*)')->toSql().')'));
})->get();
Sign up to request clarification or add additional context in comments.

8 Comments

Great trick! but this doesn't works because of line DB::raw('('.(clone $documentTypes)->selectRaw('count(*)')->toSql().')') that converts to a sql string instead of a number that's what the parameter expects...
Did you try the query?
Look at Laravel API: whereHas(string $relation, Closure $callback, string $operator = '>=', int $count = 1)
You can still pass a raw expression. Replace ->get() with ->toSql() and look at the result.
There's no way to execute this select before and pass his return value to the integer parameter?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.