バンドルのスケルトン生成
php ezpublish/console generate:bundle \
--namespace=EzSystems/TweetFieldTypeBundle \
--bundle-name=EzSystemsTweetFieldTypeBundle \
--dir=src \
--format=yml
Do you want to generate the whole directory structure [no]? no<enter>
バンドルの構造
eZ
└── Publish
└── FieldType
└── Tweet
├── Type.php
└── Value.php
Type クラス
Type にはフィールドタイプのロジックが含まれる:データのバリデーション、さまざまなフォーマットからの変換、バリデーターの説明...
Type クラスは eZ\Publish\SPI\FieldType\FieldType
を実装する必要がある。また、eZ\Publish\Core\FieldType\FieldType
抽象クラスを拡張することもできる。
Value クラス
Value はコンテンツアイテム内のタイプのインスタンスを表すために使用される。各フィールドは Type の Value クラスのインスタンスを使用してデータを出力する。
Value クラスは eZ\Publish\SPI\FieldType\Value
を実装する必要がある。また、eZ\Publish\Core\FieldType\Value
抽象クラスを拡張することもできる。
Tweet\Value クラスの実装
FieldType の Value クラスは設計上は非常にシンプルである。ステートレスで、できるだけ軽量であることを意図している。従って、Type クラスの責任として、このクラスはできるだけロジックを含まないようにしなくてはならない。
Value には少なくとも以下が含まれる:
- パブリックプロパティー(実際のデータを格納するために使用)
-
__toString()
メソッドの実装(継承する Value インタフェースで必要)
デフォルトでは、FieldType\Value
のコンストラクタが使用され、プロパティ/値のペアのハッシュを渡すことができる。この例では、必要に応じて上書きすることができる。
Tweet FieldType は3つのものを保存する:
- ツイートの URL
- ツイートのオーサーの URL
- 本文(HTML 文字列として)
ここでは格納される場所は考慮しない。FieldType を API として公開することのみ。以下のプロパティで終わる:
/**
* Tweet URL on twitter.com (http://twitter.com/UserName/status/id).
* @var string
*/
public $url;
/**
* Author's tweet URL (http://twitter.com/UserName)
* @var string
*/
public $authorUrl;
/**
* The tweet's embed HTML
* @var string
*/
public $contents;
FieldType\Value
インターフェイスに残るのは __toString()
メソッドのみ。ツイートの URL を返そう。
public function __toString()
{
return $this->url;
}
Tweet\Type クラスの実装
識別メソッド: getFieldTypeIdentifier()
この FieldType を一意に識別する文字列 (eZ Publish 4 の DataTypeString) を返す必要がある。
public function getFieldTypeIdentifier()
{
return 'eztweet';
}
Value 処理メソッド: createValueFromInput()
と checkValueStructure()
両メソッドは acceptValue()
の抽象 FieldType 実装で使われる。この FieldType インターフェースメソッドはさまざまな入力値をチェックし、type 自身の Value クラス (eZ\FieldType\Tweet\Value
) に変換する。このメソッドは以下のいずれかの必要がある。
- 入力値から作成できた Value オブジェクトを返す
- この値を変更しないで返す。 API はこれを検出し、入力値が受け入れられなかったことを通知する。
この type に許容される値はツイートの URL のみ。
protected function createValueFromInput( $inputValue )
{
if ( is_string( $inputValue ) )
{
$inputValue = new Value( array( 'url' => $inputValue ) );
}
return $inputValue;
}
このメソッドを使用して、API を使用して属性の値を設定する便利な方法を提供する。単純なものから複雑なビジネスオブジェクトまで何でもよい。
次に checkValueStructure()
を実装する。これは Type に供給される Value が受け入れられることを保証するために抽象 FieldType によって呼び出される。ここでは Tweet\Value::$url
が文字列であることを確認する。
protected function checkValueStructure( BaseValue $value )
{
if ( !is_string( $value->url ) )
{
throw new eZ\Publish\Core\Base\Exceptions\InvalidArgumentType(
'$value->url',
'string',
$value->url
);
}
}
public function getEmptyValue()
{
return new Value;
}
array(
'StringLengthValidator' => array(
'minStringLength' => 0,
'maxStringLength' => 100
)
);
array(
‘TweetAuthorValidator’ => array(
‘AuthorList’ => array( ‘johndoe’, ‘janedoe’ )
)
);
public function validateValidatorConfiguration( $validatorConfiguration )
{
$validationErrors = array();
foreach ( $validatorConfiguration as $validatorIdentifier => $constraints )
{
// Report unknown validators
if ( !$validatorIdentifier != 'TweetAuthorValidator' )
{
$validationErrors[] = new ValidationError( "Validator '$validatorIdentifier' is unknown" );
continue;
}
// Validate arguments from TweetAuthorValidator
if ( !isset( $constraints['AuthorList'] ) || !is_array( $constraints['AuthorList'] ) )
{
$validationErrors[] = new ValidationError( "Missing or invalid AuthorList argument" );
continue;
}
foreach ( $constraints['AuthorList'] as $authorName )
{
if ( !preg_match( '/^[a-z0-9_]{1,15}$/i', $authorName ) )
{
$validationErrors[] = new ValidationError( "Invalid twitter username" );
}
}
}
return $validationErrors;
}
public function validate( FieldDefinition $fieldDefinition, SPIValue $fieldValue )
{
$errors = array();
if ( $this->isEmptyValue( $fieldValue ) )
{
return $errors;
}
// Tweet Url validation
if ( !preg_match( '#^https?://twitter.com/([^/]+)/status/[0-9]+$#', $fieldValue->url, $m ) )
$errors[] = new ValidationError( "Invalid twitter status url %url%", null, array( $fieldValue->url ) );
$validatorConfiguration = $fieldDefinition->getValidatorConfiguration();
if ( isset( $validatorConfiguration['TweetAuthorValidator'] ) )
{
if ( !in_array( $m[1], $validatorConfiguration['TweetAuthorValidator']['AuthorList'] ) )
{
$errors[] = new ValidationError(
"Twitter user %user% is not in the approved author list",
null,
array( $m[1] )
);
}
}
return $errors;
}
public function getName( SPIValue $value )
{
return preg_replace(
'#^https?://twitter\.com/([^/]+)/status/([0-9]+)$#',
'$1-$2',
(string)$value->url );
}
protected function getSortInfo( CoreValue $value )
{
return $this->getName( $value );
}
public function fromHash( $hash )
{
if ( $hash === null )
{
return $this->getEmptyValue();
}
return new Value( $hash );
}
public function toHash( SPIValue $value )
{
if ( $this->isEmptyValue( $value ) )
{
return null;
}
return array(
'url' => $value->url
);
}
/**
* @param \EzSystems\TweetFieldTypeBundle\eZ\Publish\FieldType\Tweet\Value $value
* @return \eZ\Publish\SPI\Persistence\Content\FieldValue
*/
public function toPersistenceValue( SPIValue $value )
{
if ( $value === null )
{
return new PersistenceValue(
array(
"data" => null,
"externalData" => null,
"sortKey" => null,
)
);
}
return new PersistenceValue(
array(
"data" => $this->toHash( $value ),
"sortKey" => $this->getSortInfo( $value ),
)
);
}
/**
* @param \eZ\Publish\SPI\Persistence\Content\FieldValue $fieldValue
* @return \EzSystems\TweetFieldTypeBundle\eZ\Publish\FieldType\Tweet\Value
*/
public function fromPersistenceValue( PersistenceValue $fieldValue )
{
if ( $fieldValue->data === null )
{
return $this->getEmptyValue();
}
return new Value( $fieldValue->data );
}
use EzSystems\TweetFieldTypeBundle\Twitter\TwitterClientInterface;
class Type extends FieldType
{
/** @var TwitterClientInterface */
protected $twitterClient;
public function __construct( TwitterClientInterface $twitterClient )
{
$this->twitterClient = $twitterClient;
}
}
public function toPersistenceValue( SPIValue $value )
{
// if ( $value === null )
// {...}
if ( $value->contents === null )
{
$value->contents = $this->twitterClient->getEmbed( $value->url );
}
return new PersistenceValue(
// array(...)
}