totalWidth() <= $availableWidth) { return $dataWidths->enforceMinimums($minimumWidths); } // Get the short columns first. If there are none, then distribute all // of the available width among the remaining columns. $shortColWidths = $this->getShortColumns($availableWidth, $dataWidths, $minimumWidths); if ($shortColWidths->isEmpty()) { return $this->distributeLongColumns($availableWidth, $dataWidths, $minimumWidths); } // If some short columns were removed, then account for the length // of the removed columns and make a recursive call (since the average // width may be higher now, if the removed columns were shorter in // length than the previous average). $availableWidth -= $shortColWidths->totalWidth(); $remainingWidths = $dataWidths->removeColumns($shortColWidths->keys()); $remainingColWidths = $this->calculate($availableWidth, $remainingWidths, $minimumWidths); return $shortColWidths->combine($remainingColWidths); } /** * Calculate the longest cell data from any row of each of the cells. */ public function calculateLongestCell($rows) { return $this->calculateColumnWidths( $rows, function ($cell) { return strlen($cell); } ); } /** * Calculate the longest word and longest line in the provided data. */ public function calculateLongestWord($rows) { return $this->calculateColumnWidths( $rows, function ($cell) { return static::longestWordLength($cell); } ); } protected function calculateColumnWidths($rows, callable $fn) { $widths = []; // Examine each row and find the longest line length and longest // word in each column. foreach ($rows as $rowkey => $row) { foreach ($row as $colkey => $cell) { $value = $fn($cell); if ((!isset($widths[$colkey]) || ($widths[$colkey] < $value))) { $widths[$colkey] = $value; } } } return new ColumnWidths($widths); } /** * Return all of the columns whose longest line length is less than or * equal to the average width. */ public function getShortColumns($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths) { $averageWidth = $dataWidths->averageWidth($availableWidth); $shortColWidths = $dataWidths->findShortColumns($averageWidth); return $shortColWidths->enforceMinimums($minimumWidths); } /** * Distribute the remainig space among the columns that were not * included in the list of "short" columns. */ public function distributeLongColumns($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths) { // First distribute the remainder without regard to the minimum widths. $result = $dataWidths->distribute($availableWidth); // Find columns that are shorter than their minimum width. $undersized = $result->findUndersizedColumns($minimumWidths); // Nothing too small? Great, we're done! if ($undersized->isEmpty()) { return $result; } // Take out the columns that are too small and redistribute the rest. $availableWidth -= $undersized->totalWidth(); $remaining = $dataWidths->removeColumns($undersized->keys()); $distributeRemaining = $this->distributeLongColumns($availableWidth, $remaining, $minimumWidths); return $undersized->combine($distributeRemaining); } /** * Return the length of the longest word in the string. * @param string $str * @return int */ protected static function longestWordLength($str) { $words = preg_split('#[ /-]#', $str); $lengths = array_map(function ($s) { return strlen($s); }, $words); return max($lengths); } }