2

关于 PSR-0 的实现以及必须从命令行执行哪些命令,我​​需要采取哪些步骤从 Kohana 3.2 升级到 3.3?

4

2 回答 2

6

Unix命令行:

这些是我在 Kohana 应用程序中实现 PSR-0 所采取的步骤。

我删除了以下系统/目录:

rm -rf system

在您当前的 bootstrap.php 中,唯一的更改是使类以大写开头,因此最好保留旧的 bo​​otstrap 并在文件顶部更改以下行:

// Load the core Kohana class
require SYSPATH.'classes/Kohana/Core'.EXT;

if (is_file(APPPATH.'classes/Kohana'.EXT))
{
  // Application extends the core
  require APPPATH.'classes/Kohana'.EXT;
}
else
{
  // Load empty core extension
  require SYSPATH.'classes/Kohana'.EXT;
}

从新的 kohana 发布目录中删除 bootstrap.php。现在将 3.3 的所有文件复制粘贴到您的旧应用程序:

cp -R path/to/new/kohana/* .

现在将所有控制器和模型移动到大写的目录并删除旧目录:

mv application/classes/controller/* application/classes/Controller
mv application/classes/model/* application/classes/Model
rm -rf application/classes/controller application/classes/model

供应商目录在 kohana 目录的根目录中有一个固定位置。将您的供应商目录从应用程序/供应商(如果有的话)移动到供应商/

mv application/vendor .

编辑数据库配置文件(例如application/config/database.php),所有“类型”属性都应该大写:

  return array
  (
    'default' => array
    (
      'type'       => 'MySQL',

当您使用 AUTH orm 驱动程序并覆盖了 application/config/auth.php 中的配置时,将驱动程序名称大写:

return array(
  'driver'       => 'ORM',

现在到了棘手的部分,这些类的所有类名和文件名都应该大写。转到类目录。

cd application/classes

并复制粘贴此命令:

  for SRC in `find . -depth`
  do DST=`dirname "${SRC}"`/`basename "${SRC}" | sed -e 's/^./\U&/'`;
      if [ "${SRC}" != "${DST}" ]
      then
        [ ! -e "${DST}" ] && mv -T "${SRC}" "${DST}" || echo "${SRC} was not renamed"
      fi
  done

(来源:http: //forum.kohanaframework.org/discussion/comment/73089#Comment_73089

此命令递归检查所有目录并将文件名大写。转到应用程序目录。

cd ../

现在在模型和控制器(和助手)中,将所有类名大写。所以 Controller_template_parent 必须变成 Controller_Template_Parent。我有一些非常低效的命令(所以请贡献)。

find ./ -name \*.php -exec sed  -i "s/helper_\([a-zA-Z]\+\)/Helper_\u\1/gI" {} \;
find ./ -name \*.php -exec sed  -i "s/helper_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)/Helper_\u\1_\u\2/gI" {} \;
find ./ -name \*.php -exec sed  -i "s/helper_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)/Helper_\u\1_\u\2_\u\3/gI" {} \;

开头的 ./ 用于所有以 .php 结尾的文件(递归目录)。我在 sed 命令后面添加了一个“I”,以使搜索不区分大小写。(源命令:https ://askubuntu.com/questions/84007/find-and-replace-text-within-multiple-files )

第一个命令将用 Helper_Some_thing_here 替换 helper_some_thing_here。第二个命令会将 helper_some_thing_here 转换为 Helper_Some_Thing_here 等。因此,如果您的类名中包含超过 3 个下划线,则可以构建自己的命令。

以 Model_ 和 Controller_ 开头的类也需要这样做

find ./ -name \*.php -exec sed  -i "s/model_\([a-zA-Z]\+\)/Model_\u\1/gI" {} \;
find ./ -name \*.php -exec sed  -i "s/model_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)/Model_\u\1_\u\2/gI" {} \;
find ./ -name \*.php -exec sed  -i "s/model_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)/Model_\u\1_\u\2_\u\3/gI" {} \;

find ./ -name \*.php -exec sed  -i "s/controller_\([a-zA-Z]\+\)/Controller_\u\1/gI" {} \;
find ./ -name \*.php -exec sed  -i "s/controller_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)/Controller_\u\1_\u\2/gI" {} \;
find ./ -name \*.php -exec sed  -i "s/controller_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)/Controller_\u\1_\u\2_\u\3/gI" {} \;

现在,一些仅使用 1 个大写字母的类名现在以全大写形式编写(Html、Url、Http、UTF8)。在整个应用程序中替换它们。

在 application/ 目录中执行此命令:

find ./ -name \*.php -exec sed -i "s/Url::/URL::/gI" {} \;
find ./ -name \*.php -exec sed -i "s/Html::/HTML::/gI" {} \;
find ./ -name \*.php -exec sed -i "s/Http::/HTTP::/gI" {} \;
find ./ -name \*.php -exec sed -i "s/Utf8::/UTF8::/gI" {} \;

当您使用 ORM 驱动程序时,您的所有 Orm::factory('some_class') 都应该大写并大写为 ORM::factory('Some_Class')。我使用相同的命令将所有 ORM 类大写并将工厂中的类名大写。

find ./ -name \*.php -exec sed -i  "s/orm::factory(\(\"\|'\)\([a-zA-Z_]\+\)\(\"\|'\)\(,[^,]*\)*)/ORM::factory('\u\2'\4)/gI" {} \;
find ./ -name \*.php -exec sed -i  "s/orm::factory(\(\"\|'\)\([a-zA-Z]\+\)_\([a-zA-Z]\+\)\(\"\|'\)\(,[^,]*\)*)/ORM::factory('\u\2_\u\3'\5)/gI" {} \;
find ./ -name \*.php -exec sed -i  "s/orm::factory(\(\"\|'\)\([a-zA-Z]\+\)_\([a-zA-Z]\+\)_\([a-zA-Z]\+\)\(\"\|'\)\(,[^,]*\)*)/ORM::factory('\u\2_\u\3_\u\4'\6)/gI" {} \;

现在我的模块从 3.3 开始不再兼容,并不是所有的模块都升级了。当您想自己升级它们时,您可能必须分别检查它们转到每个模块的类目录,将其文件和类名大写。您可以使用以前的命令。

对我来说,这是升级应用程序时的清单,就像我说的,请随时做出贡献,以便升级更容易。

于 2012-12-18T16:43:32.747 回答
3

基于 Daan 的回答和更多我写了一个 php 脚本来将 Kohana v3.2 升级到 v3.3

它在 github 上可用: https ://github.com/Choufourax/upgrade-kohana-3_2-to-3_3

或以下:

#!/usr/bin/php -q
<?php
/*

A PHP SCRIPT TO UPGRADE FROM KOHANA 3.2.X TO KOHANA 3.3.X
------------------------------------------------------

Based on the works of :  
=> Daan (http://stackoverflow.com/users/987864/daan)
http://stackoverflow.com/questions/13935621/how-to-upgrade-from-kohana-3-2-to-3-3-implementing-psr-0  
=> Alex Cartwright <alexc223@gmail.com>
https://github.com/AlexC/kohana-upgrade-script

This script is designed to do bulk changes to your codebase that can
easily be automated, changes that would otherwise have the potential
to take a very long time for a large project. It does not provide a
fully automated migration, and it is highly recommended that you read
the official Kohana 3.3 upgrade guide before running this script.
http://kohanaframework.org/3.3/guide/kohana/upgrading

------------------------------------------------------

Be smart, be safe :
BACKUP YOUR WEBSITE BEFORE RUNNING THIS SCRIPT
------------------------------------------------------

This script handles :
- Changes in Bootstrap / database config file / auth config file
- PSR-0 support (file/class naming conventions)
    - Change the file names 
    - Change the name of class in all files  (including calls, extends...)
- Case sensitive ORM, HTTP, URL, UTF8, HTML classes
- New syntax for Browser cache checking
- New syntax for Redirects (HTTP 300, 301, 302, 303, 307)
- Apply the changes listed above in Modules too
- Moving the vendor folder

This script does not handle :
- HTTP Exceptions
- Custom Error Pages (HTTP 500, 404, 403, 401 etc)
- Query Builder Identifier Escaping
- Route Filters

Things to do :
- improve regex to prevent replacement mistakes between class and functions

HOW TO USE
------------------------------------------------------

This script is to use on your local version of your website
Do not use on your production server (as you will experiment permission issues as your server is not supose to let you modify PHP files dynamically for security reasons)
Once your local site is updated and you test everything, upload files via FTP to your production server. 

1/ Backup your site

2/ Download kohana 3.3

3/ Manulay replace the following folders from Kohana 3.3 to the website to upgrade :
- system
- modules/auth
- modules/cache
- modules/codebench
- modules/database
- modules/image
- modules/minion
- modules/orm
- modules/unittest
- modules/userguide

4/ Edit the settings at the begining of the script 

5/ Run this file
   - if you use a Mac : the best way will be to open the php file with BBedit and chose in the '#!' menu "Run in Terminal"  
   - you can also open a Terminal, go to the script folder and type ./upgrade-kohana.php  
   - you can also just run the script from your local webserver http://localhost/website/upgrade-kohana.php but it's not recommended as you may have some permissions problem to modify the PHP files  

------------------------------------------------------

AUTHOR
------------------------------------------------------

@author Erwan Dupeux-Maire  
www.upyupy.fr  
www.bwat.fr  

*/


/*
---------------
SETTINGS
---------------
*/
// START OF SETTINGS
// Path to kohana v3.2 website to update 
$path = '/Library/WebServer/Documents/work/bwat/bwat/';

// List of folders to process (at least $path.'application' )
// You sould not use this script to upgrade third party modules that already have a v3.3 version.
$dirs = array (
    $path.'application',
    $path.'modules/a1',
    $path.'modules/a2',
    $path.'modules/acl',
    $path.'modules/admin',
    $path.'modules/adminfiles',
    $path.'modules/adminnl',
    /*
    $path.'modules/auth',
    $path.'modules/cache',
    $path.'modules/codebench',
    $path.'modules/database',
    $path.'modules/image',
    $path.'modules/minion',
    $path.'modules/orm',
    $path.'modules/unittest',
    $path.'modules/userguide'
    */
);

// Search and replace class name in "views" folders to update the case ?
// true => yes | false => no
$checkInViews = true;

// If there is some files you don't want to process, add them to this array
$skip = array('_notes','.DS_Store','lib-mail-phpmailer','lib-rtf');

// Special class rewrinting 
// sometimes, captialize is not enought
// Use this array to set special changes()
$specials = array (
    'upyupy' =>'UpyUpy',
    'gd' => 'GD',
    'orm' => 'ORM',
    'db' => 'DB',
    'mysql' => 'MySQL',
    'pdo' => 'PDO',
    'html' => 'HTML',
    'url' => 'URL',
    'http' => 'HTTP',
    'utf8' => 'UTF8',
    'validurl' => 'ValidURL',
    'validcolor' => 'ValidColor',
    'userfuncarray' => 'UserFuncArray',
    'urlsite' => 'URLSite',
    'stripnullbytes' => 'StripNullBytes',
    'mddoincludeviews' => 'MDDoIncludeViews',
    'mddoimageurl' => 'MDDoImageURL',
    'mddobaseurl' => 'MDDoBaseURL',
    'ltrimdigits' => 'LtrimDigits',
    'gruberurl' => 'GruberURL',
    'explodelimit' => 'ExplodeLimit',
    'datespan' => 'DateSpan',
    'autolinkemails' => 'AutoLinkEmails',
    'arrcallback' => 'ArrCallback'
);


// END OF SETTINGS


// Function to remove folders and files 
// @author : http://stackoverflow.com/users/1226894/baba
// http://stackoverflow.com/questions/9835492/move-all-files-and-folders-in-a-folder-to-another
function rrmdir($dir) {
    if (is_dir($dir)) {
        $files = scandir($dir);
        foreach ($files as $file)
            if ($file != "." && $file != "..") rrmdir("$dir/$file");
        rmdir($dir);
    }
    else if (file_exists($dir)) unlink($dir);
}
// Function to Copy folders and files       
// @author : http://stackoverflow.com/users/1226894/baba
function rcopy($src, $dst) {
    if (file_exists ( $dst ))
        rrmdir ( $dst );
    if (is_dir ( $src )) {
        mkdir ( $dst );
        $files = scandir ( $src );
        foreach ( $files as $file )
            if ($file != "." && $file != "..")
                rcopy ( "$src/$file", "$dst/$file" );
    } else if (file_exists ( $src ))
        copy ( $src, $dst );
}

// Function to search and replace in a file (not case sensitive)
// @author : Erwan Dupeux-Maire
function replaceInFile($file, $search, $replace)
{
    if (!is_file($file))
    {
        echo $file.' does not exist (replaceInFile)'."<br />\n";
        return false;
    }
    $str = str_ireplace($search, $replace, file_get_contents($file));
    return file_put_contents($file, $str);
}
// Function to search and replace in a file with regex
// @author : Erwan Dupeux-Maire
function pregReplaceInFile($file, $search, $replace)
{
    if (!is_file($file))
    {
        echo $file.' does not exist (pregReplaceInFile)'."<br />\n";
        return false;
    }
    $str = preg_replace($search, $replace, file_get_contents($file));
    return file_put_contents($file, $str);
}


function rewritteFolderFiles($dir, $shortdir)
{
    global $path, $skip, $specials;
    //echo $dir."<br />\n";

    if (!is_dir($dir))
    {
        echo $dir.' does not exist (rewritteFolderFiles)'."<br />\n";
        return array();
    }


    // let's start the fun
    $ffs = scandir($dir);
    $arr = array();
    foreach($ffs as $ff){
        if($ff != '.' && $ff != '..' && !in_array($ff, $skip))
        {
            //echo $dir.'/'.$ff."<br />\n";
            // Write classname
            $filename = str_replace(
                '.php', 
                '', 
                trim($shortdir.'/'.$ff, '/')
            );

            $arrPath = explode('/', $filename);
            foreach($arrPath as $k => $v)
            {
                if (isset($specials[strtolower($v)]))
                {
                    // in case u have some custom rewriting to do
                    $arrPath[$k] = $specials[strtolower($v)];
                }
                else
                {
                    // just capitalize
                    $arrPath[$k] = ucfirst($v);
                }
            }
            $classname = join('_',$arrPath);
            //echo $classname."<br />\n";


            if (is_file($dir.'/'.$ff) && strpos($ff, '.php')!==false)
            {
                // this array will be use to find/replace all occurences of a class name
                // Explanation and limits of this regex : see #NOTE1 at the end of this file.
                $arr['/(\(|\s|\t)('.$classname.')(\s)*(\(|\:\:|extends)/i'] = '$1'.$classname.'$3$4';

                $key = str_replace('.php', '', $ff);
                if (isset($specials[strtolower($key)]))
                {
                    // in case u have some custom rewriting to do
                    $nn = $specials[strtolower($key)].'.php';
                }
                else
                {
                    // just capitalize
                    $nn = ucfirst($ff);
                }
                // rename file
                rename($dir.'/'.$ff, $dir.'/'.$nn);
            }
            if(is_dir($dir.'/'.$ff)) 
            {
                if (isset($specials[strtolower($ff)]))
                {
                    // in case u have some custom rewriting to do
                    $nn = $specials[strtolower($ff)];
                }
                else
                {
                    // just capitalize
                    $nn = ucfirst($ff);
                }            
                // rename folder
                rename($dir.'/'.$ff, $dir.'/'.$nn);

                // merge without matching keys
                $arr = array_merge($arr, rewritteFolderFiles($dir.'/'.$ff, trim($shortdir.'/'.$ff, '/')));
            }
        }
    }
    return $arr;
}

function replaceClassNameInFolder($dir, $arrSearch, $arrReplace)
{
    global $skip;
    //echo $dir."<br />\n";

    if (!is_dir($dir))
    {
        echo $dir.' does not exist (replaceClassNameInFolder)'."<br />\n";
        return array();
    }

    $ffs = scandir($dir);
    $arr = array();
    foreach($ffs as $ff){
        if($ff != '.' && $ff != '..' && !in_array($ff, $skip))
        {
            if (is_file($dir.'/'.$ff) && strpos($ff, '.php')!==false)
            {
                $arr[] = $ff;
                pregReplaceInFile(
                    $dir.'/'.$ff,
                    $arrSearch,
                    $arrReplace
                );
            }
            if(is_dir($dir.'/'.$ff)) 
            {
                $arr[$ff] = replaceClassNameInFolder($dir.'/'.$ff, $arrSearch, $arrReplace);
            }
        }
    }
    return $arr;
}

$listOfRegexReplace = array();
foreach ($dirs as $dir)
{
    echo 'Processing '.$dir."......<br />\n";
    if ($dir == $path.'application')
    {
        // #1 manage bootstrap  
        // replace classes/kohana and classes/kohana/core
        // by classes/Kohana and classes/Kohana/Core
        replaceInFile(
            $dir.'/bootstrap.php', 
            array(
                'classes/kohana/core',
                'classes/kohana'
            ), 
            array(
                'classes/Kohana/Core',
                'classes/Kohana'
            )
        );

        // #2 move vendors
        if (file_exists($dir.'/vendor'))
        {
            rcopy($dir.'/vendor', $dir.'/../vendor' );
        }

        // #2bis add ignore_on_delete value in cache config if exists
        // (I experiment errors if ignore_on_delete is not an array in Kohana 3.3.0)
        if (file_exists($dir.'/config/cache.php'))
        {
            pregReplaceInFile(
                $dir.'/config/cache.php', 
                array(
                    '/((\'driver\')(\s)*(\=>)(\s)*(\'file\'))/i',
                ), 
                array(
                    '$1,
             \'ignore_on_delete\'   => array(
                    \'.gitignore\',
                    \'.git\',
                    \'.svn\'
             )'
                )
            );
        }
    }

    // #3 Edit the database config file, all "type" properties should be capitalised
    // should be only in application/config/database.php but may also be in modules/mymodule/config/database.php
    if (file_exists($dir.'/config/database.php'))
    {
        replaceInFile(
            $dir.'/config/database.php', 
            array(
                '\'mysql\'',
                '"mysql"',
                '"pdo"',
                '"pdo"'
            ), 
            array(
                '\'MySQL\'',
                '"MySQL"',
                '\'PDO\'',
                '"PDO"'
            )
        );      
    }

    // #4 Edit the auth config file if Auth module is used, driver name should be capitalised
    // should be only in application/config/auth.php but may also be in modules/mymodule/config/auth.php
    if (file_exists($dir.'/config/auth.php'))
    {
        replaceInFile(
            $dir.'/config/auth.php', 
            array(
                '\'orm\'',
                '"orm"',
                '\'file\'',
                '"file"'
            ), 
            array(
                '\'ORM\'',
                '"ORM"',
                '\'File\'',
                '"File"'
            )
        );      
    }

    // #5 in /classes and its subdirectories
    // rename all php files to match the case sensitive standard PSR-0
    $dir .= '/classes';
    if (!is_dir($dir))
    {
        echo $dir.' does not exist'."<br />\n";
        continue;
    }
    // Recursive function to update file and folder files and get back the list of class name to change
    $listOfRegexReplace = array_merge(
        $listOfRegexReplace,
        rewritteFolderFiles($dir, $shortdir='')
    );


}


// #10 some class names that were used with only 1 capital, are now written in full capitals (Html, Url, Http, UTF8). 
// Add them to the list of class to rewrite
$listOfRegexReplace['/(Html)(\:\:)/i'] = 'HTML$2';
$listOfRegexReplace['/(Url)(\:\:)/i'] = 'URL$2';
$listOfRegexReplace['/(Http)(\:\:)/i'] = 'HTTP$2';
$listOfRegexReplace['/(Utf8)(\:\:)/i'] = 'UTF8$2';

// #11 Replace orm::factory by ORM:factory etc....
$listOfRegexReplace['/(Orm)(\:\:)/i'] = 'ORM$2';

// #12 Update Redirects (HTTP 300, 301, 302, 303, 307)
// ->request->redirect becomes ->redirect
// Request::current()->redirect becomes HTTP::redirect
// Request::initial()->redirect becomes HTTP::redirect
$listOfRegexReplace['/(\->request)(\s)*(\->redirect)(\s)*/i'] = '->redirect';
$listOfRegexReplace['/(Request\:\:current\(\))(\s)*(\->redirect)/i'] = 'HTTP::redirect';
$listOfRegexReplace['/(Request\:\:initial\(\))(\s)*(\->redirect)/i'] = 'HTTP::redirect';

// #13 Browser cache checking (ETags)
// $this->response->check_cache becomes $this->check_cache
$listOfRegexReplace['/(\->response)(\s)*(\->check_cache)(\s)*/i'] = '->check_cache';

// If we want to harmonize the "OR" case
// $listOfRegexReplace['/ or die/i'] = ' OR die';


echo '---DISPLAY ALL REPLACEMENT REGEX ---'."<br />\n";
print_r($listOfRegexReplace);
echo '------'."<br />\n";

// #14 change all class names in php filesName in /classes
echo '---PROCESSING CLASSES---'."<br />\n";
echo '> Processing change class names '.$dir."<br />\n";
foreach ($dirs as $dir)
{
    $dir .= '/classes';
    echo 'Processing '.$dir."......<br />\n";
    echo 'This step can be long.'."<br />\n";
    replaceClassNameInFolder(
        $dir,
        array_keys($listOfRegexReplace),// arrSearch
        $listOfRegexReplace // arrSearch
    );
}

if ($checkInViews)
{

    // #15 change all class names in views files
    echo '---PROCESSING VIEWS---'."<br />\n";
    foreach ($dirs as $dir)
    {
        $dir .= '/views';
        echo 'Processing '.$dir."......<br />\n";
        echo 'This step can be long.'."<br />\n";
        replaceClassNameInFolder(
            $dir,
            array_keys($listOfRegexReplace),// arrSearch
            $listOfRegexReplace // arrSearch
        );
    }
}

/*
// #NOTE1 
// Explaination of the regex /(\(|\s|\t)(a1)(\s)*(\(|\:\:|extends)/i
// Find classname in a file : 
// - check something that start with space, tab or "("
// - followed by the name of the class (here "a1")
// - followed by one, several or no space
// - followed by "(" or ':' or "extends")
// - not cas sensitive
//
// The limit for now : can not distinct class declaration vs function declaration
// In ne following example, function a1()... should not be replace..
// 
$example = ' class a1 extends a1 () {
    function a1() {

    } 
    $title=\'a1\';
    $comment = "You shoudl take the highway a1! a1 is the fastest.";
    a1::doIt();
    $b = new a1();
    $c = Helper_Example(a1::action());
// with no indent ?
a1();
    // aaaa1bbbb
    // a1bbbb
    // aaa1
}';
$example = preg_replace(
    array('/(\(|\s|\t)(a1)(\s)*(\(|\:\:|extends)/i'), 
    array('$1A1$3$4'),
    $example
);
echo '<pre>'.($example).'</pre>';
// -----------------
// Result will be :
// -----------------
// class A1 extends A1 () {
//  function A1() {
//  
//  } 
//  $title='a1';
//  $comment = "You shoudl take the highway a1! a1 is the fastest.";
//  A1::doIt();
//  $b = new A1();
//  $c = Helper_Example(A1::action());
// // with no indent ?
// A1();
//  // aaaa1bbbb
//  // a1bbbb
//  // aaa1
// }
*/
exit();
?>
于 2013-03-29T18:28:31.187 回答