分类目录归档:Symfony

Symfony组件 之 Console

安装:

mkdir symfony-console
cd symfony-console
composer require symfony/console

创建一个命令行应用(命令在命令行应用中运行):

#新建命令行应用
vi console

#!/usr/bin/env php
<?php
if (file_exists(__DIR__.'/vendor/autoload.php')) {
    require __DIR__.'/vendor/autoload.php';
} else {
    require __DIR__.'/../../autoload.php';
}

$app = new Symfony\Component\Console\Application('Ifeeline Console', '1.0.0');

$app->run();

#添加权限
chmod +x console
#运行
./console
#运行结果
Console 1.0.0

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  help  Displays help for a command
  list  Lists commands

从输出的结果可知,用法是commad [options] [arguments]。比如直接运行./console,那就是没有直接options和arguments。这里默认有两个命令(help和list), 直接运行命令行应用时,看起来是调用list命令。

在命令行中添加命令:

# 新建src目录,存放命令
mkdir src
cd src
vi TestCommand.php

<?php

namespace Ifeeline\Console;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Question\ConfirmationQuestion;

class TestCommand extends Command
{
    protected function configure()
    {
        $this
            ->setName('test')
            ->setDescription('Test')
            ->addArgument(
                'arg',
                InputArgument::OPTIONAL,
                'Test Command argument: arg'
            )
            ->addOption(
                'opt',
                null,
                InputOption::VALUE_NONE,
                'Test Command option: opt'
            );
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $arg = $input->getArgument('arg');
        if ($arg) {
            $text = 'Test Command argument -> ' . $arg;
        } else {
            $text = 'Test Command';
        }

        if ($input->getOption('opt')) {
            $text = strtoupper($text);
        }

        $output->writeln($text);
    }
}

# 编辑composer.json文件,让命令类可以自动加载
{
    "require": {
        "symfony/console": "^4.0"
    },
    "autoload": {
        "psr-4": {
            "Ifeeline\\Console\\": "src"
        }
    }
}

# 最后composer update
composer update

添加命令到命令行应用:

#!/usr/bin/env php
<?php
if (file_exists(__DIR__.'/vendor/autoload.php')) {
    require __DIR__.'/vendor/autoload.php';
} else {
    require __DIR__.'/../../autoload.php';
}

$app = new Symfony\Component\Console\Application('Console', '1.0.0');

$app->add(new Ifeeline\Console\TestCommand);

$app->run();

运行:

./console test ifeeline
ifeeline

./console test --opt ifeeline
IFEELINE

Symfony的命令行工具包符合http://docopt.org/描述的规范。

总结来说,一个命令需要实现两个方法。一个配置命令的参数与选项,一个是命令执行主体。命令的输入与输出可用$input和$output控制。

分清楚Argument和Option:

Arguments使用空格分隔,跟在命令名称之后。它们是有顺序的,可以是可选(OPTIONAL)或者必填(REQUIRED)或者是数组(IS_ARRAY)。如果参数类型是IS_ARRAY类型,说明它可以接收多个值,由于参数是有顺序的,所以这个参数应该是最后一个定义的参数,因为参数本身是用空格分隔的

与参数不同,选项是没有顺序的(意味着你可以随意指定)并以为两个横杆开始(可以配置以一个横杆开头)。选项总是可选的,可以设置它接受一个值或没有值(让其简单作为一个布尔值,指定就是true,否则就是false)。

Option Value
InputOption::VALUE_IS_ARRAY This option accepts multiple values (e.g. --dir=/foo --dir=/bar)
InputOption::VALUE_NONE Do not accept input for this option (e.g. --yell)
InputOption::VALUE_REQUIRED This value is required (e.g. --iterations=5), the option itself is still optional
InputOption::VALUE_OPTIONAL This option may or may not have a value (e.g. --yell or --yell=loud)

在命令中运行命令:

protected function execute(InputInterface $input, OutputInterface $output)
{
    $command = $this->getApplication()->find('demo');

    $arguments = array(
        'command' => 'demo',
        'arg'    => 'ifeeline',
        '--opt'  => true,
    );

    $input = new ArrayInput($arguments);
    $returnCode = $command->run($input, $output);

    // ...
}

更多内容可参考官方文档:http://symfony.com/doc/current/components/console.html

Symfony组件 之 Finder

The Finder component finds files and directories via an intuitive fluent interface.(流式接口搜索文件和目录)

use Symfony\Component\Finder\Finder;

$finder = new Finder();
$finder->files()->in(__DIR__);

foreach ($finder as $file) {
    // Print the absolute path
    print $file->getRealpath()."\n";

    // Print the relative path to the file, omitting the filename
    print $file->getRelativePath()."\n";

    // Print the relative path to the file
    print $file->getRelativePathname()."\n";
}

Finder方法in()是唯一必须调用的方法,用来指定搜索哪个目录。Finder的方法都是流式接口,意思就是调用它的方法后返回Finder对象本身。

方法列表:

// 指定搜索路径
$finder->in(__DIR__);
$finder->files()->in(__DIR__)->in('/elsewhere');
$finder->in('src/Symfony/*/*/Resources');
$finder->in(__DIR__)->exclude('ruby'); #排除目录
$finder->ignoreUnreadableDirs()->in(__DIR__); #排除不可读目录
$finder->in('ftp://example.com/pub/'); #指定远程目录
#注册一个自定义流
use Symfony\Component\Finder\Finder;
$s3 = new \Zend_Service_Amazon_S3($key, $secret);
$s3->registerStreamWrapper("s3");
$finder = new Finder();
$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
foreach ($finder->in('s3://bucket-name') as $file) {
    // ... do something
    print $file->getFilename()."\n";
}

// 文件与目录
$finder->files(); #仅搜索文件
$finder->directories(); // 仅搜索目录
$finder->files()->followLinks(); // 跟踪符号链接
$finder->ignoreVCS(false); // 默认符号VCS文件

// 排序(排序需要先读取所有文件和目录)
$finder->sortByModifiedTime()
$finder->sortByChangedTime()
$finder->sortByAccessedTime()
$finder->sortByType()
$finder->sortByName()

// 文件名过滤
$finder->files()->name('*.php');
$finder->files()->name('/\.php$/'); #正则
$finder->files()->notName('*.rb');

// 文件内容过滤
$finder->files()->contains('lorem ipsum');
$finder->files()->contains('/lorem\s+ipsum$/i'); #正则
$finder->files()->notContains('dolor sit amet');

// 限定路径
$finder->path('some/special/dir');
$finder->path('foo/bar');
$finder->path('/^foo\/bar/');
$finder->notPath('other/dir');

// 文件大小过滤
$finder->files()->size('< 1.5K');
$finder->files()->size('>= 1K')->size('<= 2K');

//文件时间过滤(strtotime能用的格式都能用)
$finder->date('since yesterday');

//目录深度
$finder->depth('== 0');
$finder->depth('< 3');

//读取文件内容
use Symfony\Component\Finder\Finder;

$finder = new Finder();
$finder->files()->in(__DIR__);

foreach ($finder as $file) {
    $contents = $file->getContents();

    // ...
}