0
1

More than 3 years have passed since last update.

【PHP】Laravel bladeビューのリファクタリング。implode, nullチェック, 変数をタグとして出力

Posted at

個人用メモです。
rowspanおよびcolspan属性があるth/tdタグの生成に関するコードをリファクタリング。各処理の意味と実行内容を理解する。

目次

  1. リファクタリング前のコード
  2. 問題点
  3. リファクタリング完了後のコード
  4. リファクタリングの処理内容
    1. class属性に不要なスペースの除去
    2. rowspanとcolspanの除去とダブルクオテーションの追加
    3. 属性がないときの無駄なスペース除去
      1. implodeメソッド
      2. nullチェック(if文とissetメソッド)
      3. 変数をタグとして表示する{!! !!}
    4. @switchによる冗長処理の簡略化


リファクタリング前のコード

リファクタリング前のコード
@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 

処理結果例(ブラウザの表示)

image.png

結合状態のある表が作成できている。
ただしソースコードがBESTの状態になっていない。


問題点

1) class属性に不要なスペースの除去

class="article-item td_th "

<th class="article-item td_th " rowspan="2" colspan="2">


2) ソースコードで確認するとrowspanとcolspanにスペースがある + ダブルクオテーションがない

rowspan = 2

view-source-code
<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を指定すると、最初と最後の文字のabを削除し、削除後の文字列の最初と最後のabを削除する。

このように削除後に該当する1文字があればどんどん削られていく。

abを指定
> var_export( trim('abcba', 'ab'));
'c'
baを指定
 > var_export( trim('abcba', 'ba'));
'c'

文字は1文字づつ個別であり、複数文字指定しても連続した文字列とはみなされない

先頭と末尾に該当する値がない場合は削られない。

> var_export( trim('cabcbc', 'ab'));
'cabcbc'

> var_export( trim('abcbc', 'b'));
'abcbc'


2) rowspanとcolspanの除去とダブルクオテーションの追加

属性値の文字列の生成コードが不適切。

NG
$rowspan = "rowspan = $x ";
$colspan = "colspan = $y";

スペースを削除し、ダブルクオテーションをつける。
ダブルクオテーションを文字列として表示するにはエスケープが必要。(\を冒頭につける。)

OK
$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'
tagのみの場合
$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'

引数は配列が前でも後ろでもどちらでも処理結果は同じになる。

実際の処理

implodeを使ったリファクタリング
@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$tdthnullになる可能性があるため処理前にissetifを使ってnulチェックを行う。

・isset(変数)
変数が存在すればtrue、存在しない(またはnull)の時はfalseを返す。

null-check
if (isset(変数)){
  処理
}

変数をタグとして表示する{!! !!}

変数をブラウザに表示する方法として{{ }}があるが、これは文字列となり、タグとして認識されない。

NG
<{{ $opening_tag }}>

HTML
<th class=&quot;article-item td_th&quot; rowspan=&quot;2&quot; colspan=&quot;2&quot;><p id="w8w6yhdn" class="mr-body1 article-item typography ">

タグではなく文字列に変換されるため、ダブルクオートが&quotに変換されてしまう。このため属性が適用されない。

▼対処法

変数を属性やタグとして認識させるためには、{!! !!}を使う。

blade特有の記述で、波カッコ2つのうち一つをエクスクラメーションマーク(ビックリマーク)2つに変換する。

OK
<{!! $opening_tag !!}>

HTML
 <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>



うーん、かなり簡略化かつキレイなコードになった。(リファクタリング完了後のコード

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1