В PHP есть ли способ выполнить цикл по запросу и организовать его в определенный столбец на основе значения?

#php #html #laravel #html-table

#php #HTML #laravel #html-таблица

Вопрос:

Я использую Laravel и пытаюсь заполнить HTML-таблицу из запроса. Таблица из базы данных содержит столбцы, среди прочих, id , user и shift . Существует около 100 записей, и shift столбец будет содержать букву A , B C или D . Я хочу вывести его в единую HTML-таблицу, чтобы при выполнении цикла первый столбец в выводимой таблице содержал только записи с A для этого значения, второй B и так далее.

Вот мой запрос:

 Shift::orderBy('shift', 'ASC')
        ->get();
  

Это, конечно, сортирует его по алфавиту, а затем, когда я выполняю цикл, используя это:

       ...
  <tbody>
    @foreach ($shifts as $shift)
          <tr>
              <td>{{ $shift->id }}</td>
            ...
           </tr>
      @endforeach
   </tbody>
  ...
  

Или аналогичные варианты, которых я перепробовал множество, он будет проходить через все записи с помощью A и создавать эти ячейки / строки в таблице, а затем начинать с B . Но к тому времени, поскольку они уже созданы, B записи начинаются независимо от того, сколько A записей там находится в исходном состоянии.

Я зациклился на нем и создал четыре отдельные таблицы, но я бы предпочел, чтобы это было в одной. Я хочу экспортировать таблицу с помощью Laravel Excel, и если это отдельные таблицы, они просто складываются, но я хочу, чтобы они были рядом. В любом случае, вот что я имею в виду и хочу (строки с буквами будут представлять собой другую информацию в итоговой таблице):

введите описание изображения здесь

Чего я не понимаю? Я чувствую, что делаю что-то не очень простое. Спасибо за любую помощь.

Комментарии:

1. Вероятно, вам нужно пересмотреть способ хранения и извлечения ваших данных. Но если вы должны достичь этой цели, похоже, вам нужно разделить их на 4 массива, а затем снова объединить их вместе, причем каждое значение массива содержит вложенный массив с потенциальным значением для A-D.

2. Да, я подумал, что мне придется что-то с этим изменить. Я бы предпочел этого не делать, поскольку это нужно только для лучшего отображения при экспорте в электронную таблицу, а перебирать и создавать 4 таблицы намного проще. Но это уже другая тема.

Ответ №1:

Да, вы можете отсортировать их, используя usort который существует для этой цели. usort() будет отсортирован массив по значениям с использованием определяемой пользователем функции сравнения.

 $arr = [
    ['letter'=>'C'],
    ['letter'=>'A'],
    ['letter'=>'B'],
    ['letter'=>'A'],
    ['letter'=>'D'],
];

// Function to sort by provided column name
function cmp($key){
    // Returns comparision function to be used with usort
    return function($a,$b)use($key){
        return strcmp($a[$key], $b[$key]);
    };
}
usort($arr, cmp('letter'));
print_r($arr);
  

Надеюсь, это поможет,

Ответ №2:

Я бы сказал, что наиболее эффективный способ добиться этого — выполнить сортировку на уровне базы данных. Для этого вам следует использовать orderBy() метод. Также хорошим подходом было бы наличие области для этого.

 public function scopeOrderByShiftsAsc($query)
{
    return $query->orderBy('shifts', 'asc')->orderBy('created_at', 'desc');
}

// then in your controller
public function index()
{
    $users = AppUser::orderByShiftsAsc()->get();
}
  

Вы можете использовать этот способ ( orderBy() ) либо в построителе запросов, либо в цепочке методов eloquent.
Области действия запроса.

Комментарии:

1. Если я просто сгруппирую по shift (буквы A через D ), он возвращает только одну запись из каждой буквы. Если я продолжу группировать, результат просто будет таким же, как в моем исходном запросе; сначала все As, затем Bs, Cs, а затем Ds. Я делаю что-то не так?

2. Попробуйте теперь упорядочить вместо группировки.

3. Примерно таким был мой исходный запрос (за вычетом области видимости), который, я думаю, я должен был опубликовать. Он просто упорядочивает его в алфавитном порядке, так что в нем примерно по ~ 20 букв одна за другой. И все они были импортированы из электронной таблицы, поэтому время создания одинаковое. Я бы подумал, что единственный способ добиться этого путем сортировки — это каким-то образом отсортировать его, сгруппировав фрагменты A , B , C и D ; например, взять первую запись из каждой буквы, а затем просто повторить это для каждого из них. Но я бы предположил, что это должно быть сделано за пределами уровня базы данных, с массивом.

4. Извините, я в замешательстве. Вы смешиваете таблицу в HTML и таблицу в DB. Можете ли вы опубликовать структуру таблицы и жестко закодированный HTML-код или изображение нужного HTML-кода? Вам не нужно использовать реальные данные, но помогите нам лучше понять ваш запрос. Для этого следуйте этим советам.

5. Обновлено исходное сообщение. Извините за мою расплывчатость и путаницу.

Ответ №3:

Используя:

 Shift::get()->keyBy('shift')->toArray();
  

Вы получаете структуру, подобную следующей:

 $data = [
  "A" = [
    ['id' => 1, 'shift' => 'A'],
    ...
  ],
  "B" = [
    ['id' => 2, 'shift' => 'B'],
    ...
  ],
  ...
]
  

Далее вы можете выполнить итерацию по самой большой букве и создать желаемую структуру вывода:

 $letters = array_keys($data)
$maxLength = 0
foreach($letters as $letter) {
  $len = count($data[$letter]);
  if ($len > $maxLength) $maxLength = $len;
}
$output = []
for($i = 0; $i < $maxLength: $i  ) {
   $newRow = [];
   foreach($letters as $letter) {
     if (isset($data[$letter][$i])) {
       $newRow[$letter] = $data[$letter][$i]['id'];
     } else {
       $newRow[$letter] = '';
     }
   }
   $output[] = $newRow;
}
  

Затем вы можете просто передать выходные данные в файл blade и создать таблицу в виде:

 @foreach ($output as $row)
      <tr>
          <td>{{ $row['A'] }}</td>
          <td>{{ $row['B'] }}</td>
          ...
       </tr>
  @endforeach
  

Комментарии:

1. Спасибо, но разве этот запрос не приводит к тому, что в этом массиве оказываются только четыре записи (по 1 из каждой буквы, поскольку это ключ)? Для каждой буквы есть ~ 25 строк, которые мне нужно было бы собрать, а затем выполнить цикл.

2. Нет, это должно получить все.