個人用メモです。
rowspanおよびcolspan属性があるth/tdタグの生成に関するコードをリファクタリング。各処理の意味と実行内容を理解する。
目次
リファクタリング前のコード
@php
if($tdth->getRowspan() > 1){
$x = $tdth->getRowspan();
$rowspan = "rowspan = $x ";
} else {
$rowspan = "";
}
if($tdth->getColspan() > 1){
$y = $tdth->getColspan();
$colspan = "colspan = $y";
} else {
$colspan = "";
}
$rowColspan = $rowspan.$colspan;
@endphp
@switch($type)
@case('th')
<th class="{{ $classes }}" {{ $rowColspan }}>{{ $slot }}</th>
@break
@case('td')
<td class="{{ $classes }}" {{ $rowColspan }}>{{ $slot }}</td>
@break
@endswitch
処理結果例(ブラウザの表示)
結合状態のある表が作成できている。
ただしソースコードがBESTの状態になっていない。
問題点
1) class属性に不要なスペースの除去
class="article-item td_th "
<th class="article-item td_th " rowspan="2" colspan="2">
2) ソースコードで確認するとrowspanとcolspanにスペースがある + ダブルクオテーションがない
rowspan = 2
<td class="article-item td_th " rowspan = 2 colspan = 2>
chromeが補完して読み取っているが他のブラウザでは読み込めないリスクあり。
「ページのソースを表示」で確認するの重要。
3) 属性がないときに無駄なスペースが入る
<th class="{{ $classes }}" {{ $rowColspan }}>
の属性がない場合<td >
となる。
属性がないときはシンプルに<td>
になるようにする。
エラーはないが汚い。
4) @switch
によるタグの切り分けが不要。$type
がそのまま使える。
現在の@switch
を使った条件分岐のコードが冗長。以下コードを1行で書き直すことができる。
@switch($type)
@case('th')
<th class="{{ $classes }}" {{ $rowColspan }}>{{ $slot }}</th>
@break
@case('td')
<td class="{{ $classes }}" {{ $rowColspan }}>{{ $slot }}</td>
@break
@endswitch
リファクタリング完了後のコード
@php
$attrs = [$type];
if (isset($classes)) {
$class_str = trim($classes);
$attrs[] = "class=\"$class_str\"";
}
if (isset($tdth)) {
if($tdth->getRowspan() > 1){
$x = $tdth->getRowspan();
$attrs[] = "rowspan=\"$x\"";
}
if($tdth->getColspan() > 1){
$y = $tdth->getColspan();
$attrs[] = "colspan=\"$y\"";
}
}
$opening_tag = implode(" ", $attrs);
@endphp
<{!! $opening_tag !!}>{{ $slot }}</{{$type}}>
リファクタリングの処理内容
1) class属性に不要なスペースが入っている
trim
メソッドを使うことで余計なスペースを削除することができる。
$class="article-item td_th ";
$class = trim($class);
#確認
var_export($class);
'article-item td_th'
▼trimメソッドについて
trimは文字列の先頭と末尾の空白などを削除する。
配列に対しては使えない。要素を一つづつ抜き出しtrimを適用する。
trim(文字列)
削除対象は、空白、タブ、リターン、改行、null、垂直タブ。\n\r\t\v\0
つまり、デフォルトの指定は以下と同じ。
・trim(文字列, "\n\r\t\v\0")
第2引数ありの場合
第2引数を削除対象の文字列を任意で指定することも可能。
2文字以上指定した場合はクセがあるので注意が必要。
例えばab
を指定すると、最初と最後の文字のa
かb
を削除し、削除後の文字列の最初と最後のa
かb
を削除する。
このように削除後に該当する1文字があればどんどん削られていく。
> var_export( trim('abcba', 'ab'));
'c'
> var_export( trim('abcba', 'ba'));
'c'
文字は1文字づつ個別であり、複数文字指定しても連続した文字列とはみなされない。
先頭と末尾に該当する値がない場合は削られない。
> var_export( trim('cabcbc', 'ab'));
'cabcbc'
> var_export( trim('abcbc', 'b'));
'abcbc'
2) rowspanとcolspanの除去とダブルクオテーションの追加
属性値の文字列の生成コードが不適切。
$rowspan = "rowspan = $x ";
$colspan = "colspan = $y";
スペースを削除し、ダブルクオテーションをつける。
ダブルクオテーションを文字列として表示するにはエスケープが必要。(\
を冒頭につける。)
$rowspan = "rowspan=\"$x\"";
$colspan = "colspan=\"$y\"";
補足:
\
はmacなら、option + ¥
3) 属性がないときの無駄なスペース除去
th class="{{ $classes }}" {{ $rowColspan }}
を丸ごとセットで作成する。
開始タグとそれぞれの属性、th
, class=
, rowspan=
, colspan=
をつなぎ合わせる。存在しない場合は""
でつなげる。
implodeメソッドを使用する。implodeメソッドは配列の要素を文字列としてつなげる。
▼implodeメソッド
・implode(結合する文字, 配列)
- 結合する文字と配列が逆でも問題なく動く。
- 各要素を空白でつなげたいため
implode(" ", 配列)
とする。
処理内容のイメージは以下。(簡略化のためダブルクオテーションは無視)
$arr = ["tag", "class=test", "rowspan=2", "colspan=3"];
#implode処理後の出力結果
var_export(implode(" ", $arr));
'tag class=test rowspan=2 colspan=3'
$arr = ["tag"];
var_export(implode(" ", $arr));
#出力(スペースが入らない)
'tag'
▼引数が逆の場合
$arr = ["tag", "class=test", "rowspan=2", "colspan=3"];
#引数が逆
var_export(implode($arr, " "));
'tag class=test rowspan=2 colspan=3'
引数は配列が前でも後ろでもどちらでも処理結果は同じになる。
実際の処理
@php
$attrs = [$type];
if (isset($classes)) {
$class_str = trim($classes);
$attrs[] = "class=\"$class_str\"";
}
if (isset($tdth)) {
if($tdth->getRowspan() > 1){
$x = $tdth->getRowspan();
$attrs[] = "rowspan=\"$x\"";
}
if($tdth->getColspan() > 1){
$y = $tdth->getColspan();
$attrs[] = "colspan=\"$y\"";
}
}
$opening_tag = implode(" ", $attrs);
@endphp
@switch($type)
@case('th')
<{!! $opening_tag !!}>{{ $slot }}</th>
@break
@case('td')
<{!! $opening_tag !!}>{{ $slot }}</td>
@break
@endswitch
nullチェック(if文とissetメソッド)
$class
と$tdth
はnull
になる可能性があるため処理前にisset
とif
を使ってnulチェックを行う。
・isset(変数)
変数が存在すればtrue、存在しない(またはnull)の時はfalseを返す。
if (isset(変数)){
処理
}
変数をタグとして表示する{!! !!}
変数をブラウザに表示する方法として{{ }}
があるが、これは文字列となり、タグとして認識されない。
<{{ $opening_tag }}>
↓
<th class="article-item td_th" rowspan="2" colspan="2"><p id="w8w6yhdn" class="mr-body1 article-item typography ">
タグではなく文字列に変換されるため、ダブルクオートが"
に変換されてしまう。このため属性が適用されない。
▼対処法
変数を属性やタグとして認識させるためには、{!! !!}
を使う。
blade特有の記述で、波カッコ2つのうち一つをエクスクラメーションマーク(ビックリマーク)2つに変換する。
<{!! $opening_tag !!}>
↓
<th class="article-item td_th" rowspan="2" colspan="2">
4) @switch
による冗長処理の簡略化
@switch($type)
@case('th')
<{!! $opening_tag !!}>{{ $slot }}</th>
@break
@case('td')
<{!! $opening_tag !!}>{{ $slot }}</td>
@break
@endswitch
$type
は状況に応じてtd
, th
が入るため、switch
で分岐せず、そのまま$type
を使えばいい。
<{!! $opening_tag !!}>{{ $slot }}</$type>
うーん、かなり簡略化かつキレイなコードになった。(リファクタリング完了後のコード)