小さなチャンクに分割
問題に対処する最も簡単な方法は、各ビットを個別に調べることです。以下のコードを参照してください。
/**
* Turn the array of photos into 2 equal height columns
*
* @param array photos - array of photos
* @return string
*/
function printPhotos($photos) {
$cells = buildCells($photos);
return renderColumns($cells);
}
/**
* Take the input array, and build an indexed array
*
* Use variable references to construct portrait and landscape arrays,
* and maintain an ordered list such that the original order (after
* accounting for the cell logic) is maintained.
* If at the end there is one portrait image on its own - delete it.
*
* @param array photos - array of photos
* @return array
*/
function buildCells($photos) {
$return = array(
'ordered' => array(),
'landscape' => array(),
'portrait' => array()
);
$i = 0;
foreach($photos as $photo) {
unset($cell);
$orientation = $photo['orientation'];
if ($orientation === 'portrait') {
if (empty($return['portrait'][$i])) {
$cell = array();
$return['portrait'][$i] =& $cell;
$return['ordered'][] =& $cell;
} else {
$cell =& $return['portrait'][$i];
}
$cell[] = $photo;
if (count($cell) === 2) {
$i++;
}
} else {
$cell = array($photo);
$return['landscape'][] =& $cell;
$return['ordered'][] =& $cell;
}
}
if (count($return['portrait'][$i]) === 1) {
$return['portrait'][$i] = null;
$return['portrait'] = array_filter($return['portrait']);
$return['ordered'] = array_filter($return['ordered']);
}
return $return;
}
/**
* Convert the output of buildCells into html
*
* @param array cells - indexed array of cells
* @return string column html
*/
function renderColumns($cells) {
$orderedCells = renderCells($cells);
$cellsPerColumn = (int)(count($orderedCells) / 2);
$columns = array_slice(array_chunk($orderedCells, $cellsPerColumn), 0, 2);
$return = '';
foreach($columns as $cellsInColumn) {
$return .= "<div class=\"column\">\n";
$return .= implode('', $cellsInColumn);
$return .= "</div>\n";
}
return $return;
}
/**
* Process portrait and landscape photo-cells
*
* Converts the array representation of cells into html, and returns
* The cells in presentation order
*
* @param array cells - indexed array of cells
* @return array
*/
function renderCells($cells) {
foreach(array('landscape', 'portrait') as $orientation) {
foreach($cells[$orientation] as &$cell) {
$cell = renderCell($cell, $orientation);
}
}
return $cells['ordered'];
}
/**
* For each photo in the cell - turn it into html
*
* @param array cell - array of photo(s)
* @param string orientation
* @return string
*/
function renderCell(&$cell, $orientation) {
$return = "\t<div class=\"cell\">\n";
foreach($cell as $photo) {
$return .= renderPhoto($photo, $orientation);
}
$return .= "\t</div>\n";
return $return;
}
/**
* Convert the photo into a html string
*
* @param array photo
* @param string orientation
* @return string
*/
function renderPhoto($photo, $orientation) {
if ($orientation === 'landscape') {
$src = $photo['src'];
} else {
$src = $photo['src_medium'];
}
$caption = htmlentities($photo['caption'], ENT_QUOTES);
$return = "\t\t<div class=\"$orientation thumbnail\">\n";
$return .= "\t\t\t<a href=\"{$photo['link']}\"><img src=\"$src\" alt=\"$caption\"></a>\n";
$return .= "\t\t</div>\n";
return $return;
}
1 つのことを行う関数を作成することにより、コードが期待どおりに機能することを確認することが非常に簡単になります。質問には、コードの単一のチャンクとして記述されている場合、満たされていることを確認するのが難しい要件が多数あります。
主な機能はbuildCells
.
例
この例のデータを考えると:
$data = array(
array('src' => 'x', 'src_medium' => 'y', 'orientation' => 'landscape', 'link' => 'z', 'caption' => 'one'),
array('src' => 'x', 'src_medium' => 'y', 'orientation' => 'portrait', 'link' => 'z', 'caption' => 'two'),
array('src' => 'x', 'src_medium' => 'y', 'orientation' => 'portrait', 'link' => 'z', 'caption' => 'three'),
array('src' => 'x', 'src_medium' => 'y', 'orientation' => 'portrait', 'link' => 'z', 'caption' => 'four'),
array('src' => 'x', 'src_medium' => 'y', 'orientation' => 'landscape', 'link' => 'z', 'caption' => 'five'),
array('src' => 'x', 'src_medium' => 'y', 'orientation' => 'portrait', 'link' => 'z', 'caption' => 'six'),
array('src' => 'x', 'src_medium' => 'y', 'orientation' => 'portrait', 'link' => 'z', 'caption' => 'seven')
);
echo printPhotos($data);
質問に含まれているコードの出力は次のとおりです。
<div class="column">
<div class="cell">
<div class="landscape thumbnail">
<a href="z"><img src="x" alt="one"></a>
</div>
</div>
<div class="cell">
<div class="portrait thumbnail">
<a href="z"><img src="y" alt="two"></a>
</div>
<div class="portrait thumbnail">
<a href="z"><img src="y" alt="three"></a>
</div>
</div>
</div>
<div class="column">
<div class="cell">
<div class="portrait thumbnail">
<a href="z"><img src="y" alt="four"></a>
</div>
<div class="portrait thumbnail">
<a href="z"><img src="y" alt="six"></a>
</div>
</div>
<div class="cell">
<div class="landscape thumbnail">
<a href="z"><img src="x" alt="five"></a>
</div>
</div>
</div>
いくつかのメモ/分析が続きます。
2 つの同じ高さの柱
このメソッドrenderColumns
は、ネストされた写真データの配列を受け取り、最初にそれを html 文字列のフラットな配列に変換します。このメソッドは、各 html 文字列が同じサイズ (1 つの横長の画像、または 2 つの縦長の画像が並んでいる) であることを前提としています。HTML スニペットの数が奇数の場合、最後のスニペットが削除されます。
単独のポートレート画像はありません
このメソッドbuildCells
は、最後のポートレート画像が単独であるかどうかを確認し、そうである場合は削除します。これが希望どおりでない場合は、return ステートメントの直前の行を削除して、唯一のポートレート画像を削除してください。
「セル」の追加マークアップ
結果のスタイルを設定する方が簡単な場合があります-2つの画像を一貫したHTMLでラップする-このため、セル div: のマークアップを追加しましたdiv.column > div.cell > div.thumbnail > img
。それが望ましくない場合は、簡単に削除できます。
div.thumbnail
質問よりも多くのマークアップがない限り、それは必要ないことに注意してください。
またはjsでそれを行う
それぞれ同じ作者による 2 つの js ソリューションがあり、php で行っていることと js で似たようなことを行います: masonryとisotopeです。js を使用すると、さまざまな (2 つだけでなく) サイズの画像や、最終的な html が予想とは異なるサイズになる原因となるその他のレンダリングの癖を説明するのがはるかに簡単になります。