CakePHP3でプロジェクト作成

Windows系のプロジェクトをたくさん作りましたが、
WEB系はプロジェクトマネージャーとHTML作成の経験しかないでした。

今回はcakephp３で、一からプロジェクトを作って見ます。

１、ローカル環境構築
２、DBテーブル
３、Bakeしてみよう
４、汎用SQLの利用方法
５、Global変数
６、Global関数
７、ControllerからViewへ複数の変数を渡す
８、エクセルファイル読み込む
９、エクセルファイル書きだす
１０、サーバー環境構築
１１、Templateビューの編集

１、ローカル環境構築
　　参照サイト：
　　http://tech.pjin.jp/blog/2016/06/30/howto-baking-bulletinboard/

　　XAMPPのインストールサイト：
　　https://www.apachefriends.org/jp/index.html


　　CakePHPのダウンロードサイト
　　http://www.phpbook.jp/cakephp/install/index1.html

２、テーブル
　今回のプロジェクトは１３のテーブルがあります。
![10000001.jpg](https://qiita-image-store.s3.amazonaws.com/0/195946/c21ed2b4-e278-f408-80c7-49e568680245.jpeg)

マスターデータ設定は、CSVファイルをインポートする。

３、BAKEしてみよう

htdocs/gramanagerにて、下記のコマンドを実行した。

#php bin/cake.php bake all gramanager

NetBeansエディターで開けてみたら、この感じです。
※NetBeansでctpファイルが認識できなかった問題は、下記サイトを参照して解決しました。
http://gomocool.net/gomokulog/?p=117

![image.png](https://qiita-image-store.s3.amazonaws.com/0/195946/8430caee-06bd-f6d1-874a-c0e71601b5fd.png)


４、汎用SQLの利用方法
コントローラーに下記参照を追加したら、汎用SQLでデータを取れます。
登録・更新・削除もできます。

use Cake\ORM\TableRegistry;
use Cake\Datasource\ConnectionManager;

 //ログイン者の漢字名を取得
    
     public function cal_user_janame($manager_id) {
            
           $janame='';
         
            $connection = ConnectionManager::get('default');
            
            $statement = "SELECT * FROM managers WHERE managers.id = '$manager_id'";
                        
            $stmt = $connection->execute( $statement)->fetchAll('assoc');
                    
            foreach ($stmt as $row) {
               
                $janame = $row['name'] ;
                
                $GLOBALS["current_directorA"]= $row['directora_id'];
                $GLOBALS["current_directorB"]= $row['directorb_id'];
                $GLOBALS["current_directorC"]= $row['directorc_id'];
                
             }
       
          return   $janame;
     }

５、Global変数

　　　App\Controllerに、このように定義できます。

　　　$GLOBALS['current_user_id']=$this->Auth->user('name');

参照：PHP $GLOBALS（グローバル変数）のすべて！
http://wepicks.net/phpref-globals/

６、Global関数

 //ログイン者の漢字名を取得
    
     public function cal_user_janame($manager_id) {

｝

７、ControllerからViewへ複数の変数を渡す
　自動作成されたコードは、１テーブルの全データをcontrollerから、ctpへ渡す。

　複数のデータを渡すのは、Controllerに定義できます。

 public function index()
    {
        $this->paginate = [
             'limit' => 50,
            'contain' => ['Managers']
        ];
        
        $homes = $this->paginate($this->Homes);

        $this->set(compact('homes'));
        $this->set('_serialize', ['homes']);

　　　　↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑　　条件なしなら、テーブルのデータを丸ごと渡す。
        
        
        $manager_id=$GLOBALS["current_manager_id"];
        $year_number=$GLOBALS["current_year"];
        $sec=$GLOBALS["current_sec"];  
        
        $this->paginate = [
                        'limit' => 50,
                        'contain' => ['Managers'] 
                       ,'conditions' =>array(
                           'and' => array(
                                'Homes.year_number' =>  $GLOBALS["current_year"],
                                'Homes.sec' =>  $GLOBALS["current_sec"],
                                'Homes.manager_id' => $GLOBALS["current_manager_id"]
                           ))
                        ,'group' => 'Homes.manager_id'
                        ,'order' => array('Homes.manager_id') 
                        ];    
        
        $homes_self = $this->paginate($this->Homes);
        $this->set(compact('homes_self'));

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑　　一部のデータ
        
        
        $this->paginate = [
                        'limit' => 50,
                        'contain' => ['Managers'] 
                       ,'conditions' =>array(
                           'and' => array(
                                'Homes.year_number' =>  $GLOBALS["current_year"],
                                'Homes.sec' =>  $GLOBALS["current_sec"],
                                'Homes.dira_shainid' => $GLOBALS["current_user_id"]
                           ))
                        ,'group' => 'Homes.manager_id'
                        ,'order' => array('Homes.manager_id') 
                        ];    
        
        $homes_A = $this->paginate($this->Homes);
        $this->set(compact('homes_A'));
        
        ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑　　一部のデータ
               
    }

ビュー側：
 
タイトル
<table cellpadding="0" cellspacing="0" >
       
        <thead valign="top">
            <tr>
                <th scope="col" class="actions"><?= __('AA') ?></th>
                <th scope="col" class="actions"><?= __('AAAAA') ?></th>
                <th scope="col" class="actions"><?= __('AAAA') ?></th>
                <th scope="col" class="actions"><?= __('AAA') ?></th>
                <th scope="col" class="actions"><?= __('A') ?></th>
                <th scope="col" class="actions"><?= __('A') ?></th>
                <th scope="col" class="actions"><?= __('A') ?></th>
                <th scope="col" class="actions"><?= __('A') ?></th>
                <th scope="col" class="actions"><?= __('Action') ?></th>
            </tr>
        </thead>
    </table>
    

    条件A：
    <?php if ($GLOBALS['current_rank_id'] < 7 and $GLOBALS['current_rank_id'] >2) : ?>
        
          <h5>本人</h5> 
           <table cellpadding="0" cellspacing="0">
               
                 <?php foreach ($homes_self as $home_self): ?>    
                  <tr>  
                    <td><?= $home_self->has('manager') ? $this->Html->link($home_self->manager->name, ['controller' => 　　　　　　　　　　　　　'Targets', 'action' => 'index', $home_self->manager->id]) : '' ?></td>
                    <td><?= h($home_self->target_put) ?></td>
                    <td><?= h($home_self->dir_permission) ?></td>         
                    <td><?= h($home_self->self_put) ?></td>                
                    <td><?= h($home_self->director_aput) ?></td>
                    <td><?= h($home_self->director_bput) ?></td>
                    <td><?= h($home_self->director_cput) ?></td>
                    <td><?= h($home_self->director_over) ?></td>

                    <td class="actions">
                        <?= $this->Html->link(__('編集'), ['action' => 'edit', $home_self->id]) ?>
                    </td>

                 </tr>
                 <?php endforeach; ?>
            </table>   
          
    <?php endif; ?>
      
  

条件B              
    <?php 
     if ($GLOBALS['current_rank_id'] < 5 or $GLOBALS['current_rank_id'] ==7)   {
       echo "<h5>一次</h5>" ; 
       }
    ?>

        <table cellpadding="0" cellspacing="0">

         <?php foreach ($homes_A as $home_A): ?>
            <tr>

            <td><?= $home_A->has('manager') ? $this->Html->link($home_A->manager->name, ['controller' => 'Targets', 　　　　　　　　　'action' => 'index', $home_A->manager->id]) : '' ?></td>
            <td><?= h($home_A->target_put) ?></td>
            <td><?= h($home_A->dir_permission) ?></td>      
            <td><?= h($home_A->self_put) ?></td>      
            <td><?= h($home_A->director_aput) ?></td>
            <td><?= h($home_A->director_bput) ?></td>
            <td><?= h($home_A->director_cput) ?></td>
            <td><?= h($home_A->director_over) ?></td>

            <td class="actions">
                <?= $this->Html->link(__('編集'), ['action' => 'edit', $home_A->id]) ?>
            </td>

            </tr>
          <?php endforeach; ?>
          </table>   



８、エクセルファイル読み込む
エクセルファイルのデータををDBへ読み込む出来ます。

・PHPExcelのインストール

https://github.com/PHPOffice/PHPExcel

上記URLにアクセスし、Clone or downloadボタンをクリックします。
さらに「Download Zip」をクリックすると、zipファイルがダウンロードされます。
（2017/8/24時点 のファイル名は PHPExcel-1.8.zip）

ダウンロードしたzipファイルを解凍し、
解凍フォルダ内のClassesフォルダの中身を全て、使用したいphpファイルが読み込める場所にコピーします。
自分はすべてtmpに保存しました。
Documentationフォルダ、Examplesフォルダ等は不要です。


・モデルなしのUploadsControllerとupload formを利用します。　　

UploadsControllerのコード：

<?php
namespace App\Controller;

use App\Form\UploadForm;
use Cake\Datasource\ConnectionManager;
use Cake\I18n\Time;

require_once(realpath(TMP).DS."classes".DS."PHPExcel.php");
require_once(realpath(TMP).DS."classes".DS."PHPExcel".DS."IOFactory.php");
use PHPExcel_IOFactory;

class UploadsController extends AppController
{
    public function index()
    {
        $upload = new UploadForm();

        if ($this->request->is('post')) {
       
            if ($upload->readFromExcel($this->request->data['file']['tmp_name'])) {
                $this->Flash->success('アップロードが成功しました');
  
                echo "<br/>";
                echo $this->request->data('file.name')." を正常インポートしました。";
                echo "<br/>";
                
            } else {
                $this->Flash->error('バリデーションに引っかかりました。');
                echo $this->request->data('file.name')."をインポートできませんでした。";
            }
        }

        $this->set('upload', $upload);
    }  
}


UploadFormのコード：

<?php

namespace App\Form;

use app\Controller\AppController;
use Cake\Form\Form;
use Cake\Form\Schema;
use Cake\Validation\Validator;

use Cake\Datasource\ConnectionManager;
use Cake\I18n\Time;

require_once(realpath(TMP).DS."classes".DS."PHPExcel.php");
require_once(realpath(TMP).DS."classes".DS."PHPExcel".DS."IOFactory.php");

use PHPExcel_IOFactory;

class UploadForm extends Form{

 // ファイル名渡したら配列返すラッパー関数
  public function readFromExcel($inputFile)
  
  {
      
  　$readFile = $inputFile;
  
    // ファイルの存在チェック
    if (!file_exists($readFile)) {
        exit($readFile. "が見つかりません。" );
    }

    // xlsxをPHPExcelに　
    $objPExcel = PHPExcel_IOFactory::load($readFile);
    $sheet = $objPExcel->getActiveSheet();

    $shainid = $sheet->getCell( 'A3' )->getValue();
   
     $upController = new AppController;

     $manager_id= $upController->get_manager_id_from_shainid($shainid);
     
     $directora_id= $upController->get_directorid($shainid,"a") ;
    
     
     $directora_shainid=$upController->get_shainid_from_directorid($directora_id,"a");
    
     
   
    $year_number=$GLOBALS["current_year"];   //計算
    $sec=$GLOBALS["current_sec"];         //計算
    
    //既存を削除
    $connection = ConnectionManager::get('default');
    $connection->delete('targets', ['year_number' => $year_number,'sec' => $sec, 'manager_id' => $manager_id]);
    
     $i=0;
        $firstLine=27;
        $cellLine = $firstLine ;
      
            for($i = 1; $i < 6; $i++){
                
                $cellB="B" .strval($cellLine);
                $cellO="O" .strval($cellLine);
                $cellAB="AB" .strval($cellLine);
                
                ・・・
                
                $mokuhyou = $sheet->getCell($cellB )->getValue();
                $plan = $sheet->getCell($cellO )->getValue();
                $weight = $sheet->getCell($cellAB )->getValue();
                
                ・・・
                date_default_timezone_set('Japan');
                $created = date('Y/m/d H:i:s');
                                
               // $connection = ConnectionManager::get('default');
                
                if ( strlen($mokuhyou) > 0) {
                
                    $connection->insert('targets', [
                        'year_number' => $year_number,
                        'sec' => $sec,
                        'subid' => $i,
                        'manager_id' => $manager_id,
                        'target' => $mokuhyou,
                        'plan' => $plan,
                        'weight' => $weight,
                        'status' => '編集中',
                        'self_coment' => $self_coment,
                        'self_degree' =>$self_degree,
                        'director_txt' => $director_txt,
                        'directora_id' => $directora_shainid,
                        'directorb_id' => $directorb_shainid,
                        'directorc_id' => $directorc_shainid,
                        'degree_a' =>  $degree_a,
                        'degree_b' =>  $degree_b,
                        'degree_c' =>  $degree_c,
                        'created' =>  $created,
                        'created_user' => $GLOBALS["current_user_janame"]]);
                 }
                 
                 
                $cellLine =  $cellLine + 4;
                
            }
             return true;
    }
}

・Upload.ctp: アップロードファイルを選択する。

<ul>
        <br/> 
        <br/>         
        <li><?= $this->Html->link(__('Home'), ['controller' =>'Homes', 'action' => 'index']) ?></li>
        <br/> 
        <br/>       
        <?= $this->Form->create($upload, ['type' => 'file']) ?>
        <div><p><?= $this->Form->file('file') ?></p></div>
        <div><?= $this->Form->button('アップロード', ['type' => 'submit','id' => 'register']) ?></div>
        <?= $this->Form->end() ?>

    </ul>


９、エクセルファイル書きだす
　参照：
　http://qiita.com/suin/items/7a8d0979b7675d6fd05b

　書き出すはアップロードよりシンプルです。
　固定のフォーマットで書き出したいので、EXCELテンプレートを事前に用意しました。

・参照設定：
<?php
namespace App\Controller;
use Cake\ORM\TableRegistry;
use Cake\Datasource\ConnectionManager;
use Cake\I18n\Time;

require_once(realpath(TMP).DS."classes".DS."PHPExcel.php");
require_once(realpath(TMP).DS."classes".DS."PHPExcel".DS."IOFactory.php");

use PHPExcel_IOFactory;


・エクセルテンプレート置く場所：
tmp/excel/template.xlsx

・ソース

public function download ($id=null){
  
    $target = $this->Targets->get($id, 
            [ 'contain' => []
              ]);
    
     // データを配置
    
    $manager_id=$target->manager_id;
    $year_number=$GLOBALS["current_year"];
    $sec=$GLOBALS["current_sec"];
    
    $shainjname=AppController::cal_user_janame($manager_id);
 
    // 入出力の情報設定
    $driPath    = realpath(TMP) . "/excel/";
    $inputPath  = $driPath . "template.xlsx";
    $sheetName  = "data_sheet";
   
   $outputFile = "output_".$shainjname.date('YmdHis'). ".xlsx";
   
    $outputPath = $driPath . $outputFile;
 
    // Excalファイル作成
    $reader = PHPExcel_IOFactory::createReader('Excel2007');
    $book  = $reader->load($inputPath);
    $sheet  = $book->getSheetByName($sheetName);
    
    if  ($sec == 1) {
        $jasec="上期";
    } else {
        $jasec="下期";
    }
    
     $sheet->setCellValue( "BY1", strval($year_number)."年度".$jasec);
   
     $connection = ConnectionManager::get('default');
    
    //タイトル情報
    //managers テーブルのデータ　↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
     
    $statementm = "SELECT * FROM managers WHERE managers.id = '$manager_id'";
    $stmtm = $connection->execute( $statementm)->fetchAll('assoc');

    foreach ($stmtm as $row) {
   
        $sheet->setCellValue( "A3", $shainid);
      　・・・    
    }
     
    
     //honbu_targets テーブルのデータ　↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
 $hstatement = "SELECT * FROM honbu_targets WHERE honbu_targets.year_number = '$year_number' and honbu_targets.section = '$sec' and honbu_targets.honbu_id = '$honbu_id' order by subid";
            
      $hstmt = $connection->execute( $hstatement)->fetchAll('assoc');
            
             $h=0;
             $hfirstLine=7;
      
            foreach ($hstmt as $hrow) {
                
                $hcellLine = $hfirstLine +$h;
               
                $hcellB="B" .strval($hcellLine);
                
                $honbu_target=$hrow['target'] ;
                
                $sheet->setCellValue( $hcellB,  $honbu_target);
                
                $h=$h+3;
            }
    
    
    //bumon_targets テーブルのデータ　↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
 
           
      $jstatement = "SELECT * FROM bumon_targets WHERE bumon_targets.year_number = '$year_number' and bumon_targets.section = '$sec' and bumon_targets.bumon_id = '$bumon_id' order by subid";
            
      $jstmt = $connection->execute( $jstatement)->fetchAll('assoc');
            
             $j=0;
             $jfirstLine=7;
      
            foreach ($jstmt as $jrow) {
                
                $jcellLine = $jfirstLine +$j;
               
                $jcellAB="AB" .strval($jcellLine);
                
                $bumon_target=$jrow['target'] ;
                
                $sheet->setCellValue( $jcellAB,  $bumon_target);
                
                $j=$j+3;
            }
    
    
     
    
    //targets テーブルのデータ　↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    
  
            
      $statement = "SELECT * FROM targets WHERE targets.year_number = '$year_number' and targets.sec = '$sec' and 　targets.manager_id = '$manager_id' order by subid";
            
      $stmt = $connection->execute( $statement)->fetchAll('assoc');
            
             $i=0;
             $firstLine=27;
      
            foreach ($stmt as $row) {
                
                $cellLine = $firstLine +$i;
               
                $cellB="B" .strval($cellLine);
                $cellO="O" .strval($cellLine);
               　・・・
                
                $mokuhyou=$row['target'] ;
                $plan=$row['plan'] ;
               ・・・
                   
                $sheet->setCellValue( $cellB, $mokuhyou);
                $sheet->setCellValue( $cellO, $plan);
                $sheet->setCellValue( $cellAB, $weight);
               　・・・・
               
                $i=$i+4;
             }
            
              //targets テーブルのデータ　↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
 
    // 保存
    $book->setActiveSheetIndex(0);
    $writer = PHPExcel_IOFactory::createWriter($book, 'Excel2007');
    $writer->save($outputPath);
    

     // ダウンロード
   header('Content-Type: application/octet-stream');
 
    ob_end_clean();//バッファのゴミ捨て
    header('Content-Disposition: attachment;filename="' . $outputFile . '"');
    header('Cache-Control: max-age=0');
    
     
    $book->setActiveSheetIndex(0);
    $writer = PHPExcel_IOFactory::createWriter($book, 'Excel2007');
     
    
    $writer->save('php://output'); 
    exit;
 
    return $this->redirect(['action' => 'index']);
}


 １０、サーバー環境構築
     CPIのサーバーを利用する。下記サイトを参照しました、
    　CPIサーバでCakePHP：
　　　http://g37.jp/2015/03/use-cakephp-in-cpi-server-vol1/

　　　/html/に、プロジェクトフォルダを丸ごとアップします。

※サーバーパス、ファイル名などは、大文字小文字を区別するので、気をつけてください。


１１、Templateビューの編集
       
  ・自動作成のコード      
         <li><?= $this->Html->link(__('テンプレート・ダウンロード'),['controller' => 'Targets', 'action' => 'get_template'])?></li>
         <li><?= $this->Html->link(__('アップロード'), ['controller' => 'Uploads', 'action' => 'index']) ?></li>
　
・PHPコード入れ
<?php
    if ($GLOBALS['current_rank_id'] < 4  or $GLOBALS['current_rank_id'] == 7 ) {
        echo "<li>",$this->Html->link(__('AAAA'), ['controller' => 'BumonTargets', 'action' => 'index']),"</li>" ;
        }
?>
        

・php endforeach／php endifの書き方

<?php if ($GLOBALS['current_rank_id'] < 7 and $GLOBALS['current_rank_id'] >2) : ?>
        
          <h5>本人</h5> 
           <table cellpadding="0" cellspacing="0">
               
                 <?php foreach ($homes_self as $home_self): ?>    
                  <tr>  
                    <td><?= $home_self->has('manager') ? $this->Html->link($home_self->manager->name, ['controller' => 　　　　　　　　　　　　'Targets', 'action' => 'index', $home_self->manager->id]) : '' ?></td>
                    <td><?= h($home_self->target_put) ?></td>
                    <td><?= h($home_self->dir_permission) ?></td>         
                    <td><?= h($home_self->self_put) ?></td>                
                    　．．．

                    <td class="actions">
                        <?= $this->Html->link(__('編集'), ['action' => 'edit', $home_self->id]) ?>
                    </td>

                 </tr>
                 <?php endforeach; ?>
            </table>   
          
    <?php endif; ?>