How to Break associated array in two groups

I have an Annual Operating Budget View for a single year.

public function view($id = null) {
$annualOperatingBudget = $this->AnnualOperatingBudgets->get($id, [
‘contain’ => [‘Azinstitutions’,
‘BudgetExpenses’,
‘BudgetExpenses.ExpenseTitles’,
‘BudgetRevenues’,
‘BudgetRevenues.RevenueTitles’]
]);

        $this->set('annualOperatingBudget', $annualOperatingBudget);
    }

In that year I have an associated table array with Budget Revenues (which is associated with a RevenuesTitles Table.

in my view I can list the Revenues titles and revenue Numbers in a foreach loop:

   <h4>Revenues</h4>
     <?php foreach ($annualOperatingBudget->budget_revenues as $revenueTitle) : ?>
             <li class="expenseList"><?= h($revenueTitle->revenue_title->revenue_title) ?></li>
      <?php  endforeach; ?>
     </td>
            <td class="nonBulletList">
            <h4>&nbsp;</h4>
       <?php foreach ($annualOperatingBudget['budget_revenues'] as $revenue){
                   $currentRevenues += $revenue->revenue;  ?>
                   <li><?= $this->Number->currency($revenue->revenue, 'USD', ['places' => 1]) ?></li>
        <?php }; ?>      

In my RevenueTitles Table I have a column with revenue_group with a value of 1 or 2.

I need to split my Revenues groups into two

. Was not sure where I can put that condition? Do I need to do that in the AnnualOperatingBudgetController? or can I add a condition on the foreach loop to filter the array based on the revenue_group.

you can convert it to collection and then https://book.cakephp.org/3.0/en/core-libraries/collections.html#Cake\Collection\Collection::filter

1 Like

Graziel’s answer is the nice one, but it is also possible to apply that filter in the view

<?php if ($revenueTitle->revenue_title->revenue_group == 1): ?>

you can avoid using the same view-code multiple times by using an element.

Another helpful approach could be to directly sort the result (when grabbing from the database) using

$myQuery->order([“revenue_group”, “asc”])

I thought of that also and tried it. But I got this error.

Only an array or \Traversable is allowed for Collection
InvalidArgumentException

This is the code I used:

public function view($id = null)
{
    $annualOperatingBudget = $this->AnnualOperatingBudgets->get($id, [
        'contain' => ['Azinstitutions', 'BudgetExpenses', 'BudgetExpenses.ExpenseTitles', 'BudgetRevenues', 'BudgetRevenues.RevenueTitles']
    ]);
    $collection = new Collection($revenueGroups);
    $revenueGroup1 = $collection->filter( function ($revenueGroup, $key) {
        return $revenueGroup->revenue_group === 1; });
    $revenueGroup2 = $collection->filter( function ($revenueGroup, $key) {
        return $revenueGroup->revenue_group === 2; });
    $this->set('annualOperatingBudget', $annualOperatingBudget);
}

The problem is that the view is an entity and I’m trying to filter an associated array in the entity.

Thank you dmuenstermann. I was able to filter it in the view as you suggested. My problem with the query approach was the same problem I have with the collection. It is an Entity and I’m trying to sort the associated array in that entity. So an Annual Operating Budget hasMany Revenues. I was trying to sort the hasMany and was not sure how to get to that.

I think it should be

$collection = new Collection($annualOperatingBudget);

as the result of the query is a collection, containing the data you require.

If I understand you correct here, you need the following ?

$myQuery->order(“BudgetRevenues.RevenueTitles”, “asc”);

If I understood well… do you want the AnnualOperatingBudgets->get query to return something like this?

[
    'Azinstitutions' => [
        // ...
    ],
    'BudgetExpenses' => [
        0 => [
            'ExpenseTitles' => [
                // ...
            ],
        ],
        // ...
    ],
    'BudgetRevenues' => [
        1 => [
            // RevenueTitles with revenue_group = 1
            0 => RevenueTitle,
            1 => RevenueTitle,
            // ...
        ],
        2 => [
            // RevenueTitles with revenue_group = 2
            0 => RevenueTitle,
            1 => RevenueTitle,
            // ...
        ]
    ]
]

You can do this with map or formatResults function. Using a function as a parameter, and then use Hash::extract in there with each AnnualOperatingBudget

I was able to accomplish it by adding the condition to the foreach loop as dmuenstermann suggested. This is how it looks
sample

the only thing left is to do the calculation for Net Tuition and fees which is Tuition and Fees minus Less Scholarship Allowance

@kenlaw
yeah thats why you need to convert it first to collection

$collection = new Collection($annualOperatingBudget->budget_revenues);

i dont see anywhere $revenueGroups in your code, anyway if you got it right its ok also : )

I like the idea of using a collection but it does not seem to return the variables. In my view I still see only the one variable.

public function view($id = null)
    {
      $annualOperatingBudget = $this->AnnualOperatingBudgets->get($id, [
           'contain' => ['Azinstitutions', 'BudgetExpenses', 'BudgetExpenses.ExpenseTitles', 'BudgetRevenues', 'BudgetRevenues.RevenueTitles']
       ]);
      $collection = new Collection($annualOperatingBudget->budget_revenues);
      $revenuesGroup1 = $collection->filter( function ($revenueGroup1, $key) {
          return $revenueGroup1->revenue_group === 1; });
      $revenuesGroup2 = $collection->filter( function ($revenueGroup2, $key) {
          return $revenueGroup2->revenue_group === 2; });
        
    $this->set('annualOperatingBudget', $annualOperatingBudget, 'revenuesGroup1', 'revenuesGroup2');
}

so in this I should see three variables:

  1. annualOperatingBudget (which is avalable in my view.ctp)
  2. revenuesGroup1
  3. revenuesGroup2

But those are not showing up as variables to call.

I get Notice (8): Undefined variable: revenuesGroup1 [ROOT\plugins\Twit\src\Template\AnnualOperatingBudgets\view.ctp, line 30]

my view line 30 looks like this:

<?php foreach ($revenuesGroup1 as $revenueTitle) : ?>
        <li class="expenseList"><?= h($revenueTitle->revenue_title->revenue_title) ?></li>
<?php endforeach; ?>

you need to use

$this->set(compact('var1', 'var2', ...))

or

$this->set('var1', $value1);
$this->set('var2', $value2); 

so with

$this->set(‘annualOperatingBudget’, $annualOperatingBudget, ‘revenuesGroup1’, ‘revenuesGroup2’);

you set annualOperatingBudget and nothing else

1 Like

that does give me the three variables but my collection variables are empty. :face_with_raised_eyebrow:

I figured it out. I changed the collection from filter to match:

$collection = new Collection($annualOperatingBudget->budget_revenues);
$revenuesGroup1 = $collection->match([‘revenue_title.revenue_group’ => 1 ]);
$revenuesGroup1 = $collection->match([‘revenue_title.revenue_group’ => 2 ]);

also revenue_group was an association of BudgetRevenues. so I has to add that table with the dot.

Thanks so much for sticking it out with me.