pecinaon/doctrine-mapper

实体 doctrine 映射器 - 将 Nette 表单映射到实体,并将实体映射到 Nette 表单,可以从表单构建实体

v1.0.7 2017-02-06 13:00 UTC

README

======

要求

DoctrineMapper 需要 PHP 5.5 或更高版本。

安装

安装 pecinaon/doctrine-mapper 的最佳方式是使用 Composer

$ composer require pecinaon/doctrine-mapper

配置

此扩展创建了一个新的配置部分 doctrineMapper,可用的配置如下所示

doctrineMapper:
	dateFormat: App\ExampleDateFormat

dateFormat 用于解析来自您格式的 DateTime,您可以更改它。此类必须实现 DoctrineMapper\Parsers\Date\IDateFormat。

<?php
namespace App;

class ExampleDateFormat implements \DoctrineMapper\Parsers\Date\IDateFormat
{

	/**
	 * Return date and time format
	 *
	 * @return string
	 */
	public function getDateTimeFormat()
	{
		return "H:i:s";
	}

	/**
	 * Return date format
	 *
	 * @return string
	 */
	public function getDateFormat()
	{
		return "d/m.y";
	}
}

将 ArrayHash (表单结果) 映射到实体

<?php
namespace App;

use DoctrineMapper\ArrayAccessEntityMapper;
use Nette\Application\UI\Form;
use Doctrine\ORM\Mapping as ORM;
use Nette\Object;
use Nette\Utils\ArrayHash;

/**
 * Example Entity
 *
 * @ORM\Entity(repositoryClass="ExampleRepository")
 * @ORM\Table(name="tp_example", indexes={
 * })
 * @author Pecina Ondřej <pecina.ondrej@gmail.com>
 */
class ExampleEntity extends Object
{

	/**
	 * @ORM\Column(length=128)
	 * @var string
	 */
	protected $name;

	/**
	 * @ORM\Id
	 * @ORM\Column(type="integer", options={"unsigned"=true})
	 * @ORM\GeneratedValue
	 * @var int
	 */
	protected  $id;

	/**
	 * @return int
	 */
	public function getId()
	{
		return $this->id;
	}

	/**
	 * @return string
	 */
	public function getName()
	{
		return $this->name;
	}

	/**
	 * @param string $name
	 * @return ExampleEntity
	 */
	public function setName($name)
	{
		$this->name = $name;
		return $this;
	}
}

class ExampleFormMapper
{
	/** @var ArrayAccessEntityMapper */
	private $arrayAccessEntityMapper;

	/**
	 * ExampleFormMapper constructor.
	 * @param ArrayAccessEntityMapper $arrayAccessEntityMapper
	 */
	public function __construct(ArrayAccessEntityMapper $arrayAccessEntityMapper)
	{
		$this->arrayAccessEntityMapper = $arrayAccessEntityMapper;
	}

	public function getForm() {
		$form = new Form();
		$form->addText('name', 'Name')
			->setRequired();

		$form->addSubmit('Sub', 'Save');

		$form->onSuccess[] = function(Form $form) {
			$entity  = new ExampleEntity();

			// array with name is not reuired - if is not set, set all values with existing properties in entity
			$this->arrayAccessEntityMapper->setToEntity($form->getValues(), $entity, ['name']);
			
			// works same like line above
			$this->arrayAccessEntityMapper->setToEntity($form->getValues(), $entity);
			
			// you can map also in this way 
			$this->arrayAccessEntityMapper->setToEntity(ArrayHash::from([
				'name'  => 'Testing name'
			]), $entity);
			// do stuff with entity
		};

		return $form;
	}
}

setToEntity 中的第三个参数是可选的,因为当它为空时,映射器会将 ArrayHash 中的所有值填充到实体中,当属性与 doctrine 实体中的同名属性存在时。映射器可以将所有关系映射 @ManyToMany, @ManyToOne - 映射器通过抛出带有主键的 Kdyby EntityManager 的相关实体存储库来将实体设置到映射实体中。

将实体映射到 Nette 表单

<?php
namespace App;

use DoctrineMapper\EntityFormMapper;
use Nette\Application\UI\Form;
use Doctrine\ORM\Mapping as ORM;
use Nette\Object;

/**
 * Example entity
 *
 * @ORM\Entity(repositoryClass="ExampleRepository")
 * @ORM\Table(name="tp_example", indexes={
 * })
 * @author Pecina Ondřej <pecina.ondrej@gmail.com>
 */
class ExampleEntity extends Object
{

	/**
	 * @ORM\Column(length=128)
	 * @var string
	 */
	protected $name;

	/**
	 * @ORM\Id
	 * @ORM\Column(type="integer", options={"unsigned"=true})
	 * @ORM\GeneratedValue
	 * @var int
	 */
	protected  $id;

	/**
	 * @return int
	 */
	public function getId()
	{
		return $this->id;
	}

	/**
	 * @return string
	 */
	public function getName()
	{
		return $this->name;
	}

	/**
	 * @param string $name
	 * @return ExampleEntity
	 */
	public function setName($name)
	{
		$this->name = $name;
		return $this;
	}
}

class ExampleFormMapper
{
	/** @var EntityFormMapper */
	private $entityFormMapper;

	/**
	 * ExampleFormMapper constructor.
	 * @param EntityFormMapper $entityFormMapper
	 */
	public function __construct(EntityFormMapper $entityFormMapper)
	{
		$this->entityFormMapper = $entityFormMapper;
	}


	public function getForm() {
		$form = new Form();
		$form->addText('name', 'Name')
			->setRequired();

		$form->addSubmit('Sub', 'Save');

		$form->onSuccess[] = function(Form $form) {
			// do stuff
		};
		
		$entity = new ExampleEntity();
		$entity->setName('Example name');

		// this line map all values in entity to form in this case set to component with name name' value "Example name"
		$this->entityFormMapper->setEntityToContainer($entity, $form);
		
		return $form;
	}
}

从实体构建表单

<?php
namespace App;

use DoctrineMapper\Builder\BuilderDefinition;
use DoctrineMapper\FormEntityBuilder;
use Nette\Application\UI\Form;
use Doctrine\ORM\Mapping as ORM;
use Nette\Object;

/**
 * Test related entity
 *
 * @ORM\Entity(repositoryClass="ExampleRepositoryRel")
 * @ORM\Table(name="tp_example_re", indexes={
 * })
 * @author Pecina Ondřej <pecina.ondrej@gmail.com>
 */
class TestExampleEntityRel extends Object
{

	/**
	 * @ORM\Column(length=128)
	 * @var string
	 */
	protected $name;

	/**
	 * @ORM\Id
	 * @ORM\Column(type="integer", options={"unsigned"=true})
	 * @ORM\GeneratedValue
	 * @var int
	 */
	protected  $id;

	/**
	 * @return int
	 */
	public function getId()
	{
		return $this->id;
	}

	/**
	 * @return string
	 */
	public function getName()
	{
		return $this->name;
	}

	/**
	 * @param string $name
	 * @return TestExampleEntityRel
	 */
	public function setName($name)
	{
		$this->name = $name;
		return $this;
	}
}

/**
 * Example entity
 *
 * @ORM\Entity(repositoryClass="ExampleRepository")
 * @ORM\Table(name="tp_example", indexes={
 * })
 * @author Pecina Ondřej <pecina.ondrej@gmail.com>
 */
class ExampleEntity extends Object
{

	/**
	 * @ORM\Column(length=128)
	 * @var string
	 */
	protected $name;

	/**
	 * @ORM\ManyToOne(targetEntity="App\TestExampleEntityRel")
	 * @ORM\JoinColumn(name="rel_id", referencedColumnName="id")
	 * @var OwnerEntity
	 */
	protected $related;

	/**
	 * @ORM\Id
	 * @ORM\Column(type="integer", options={"unsigned"=true})
	 * @ORM\GeneratedValue
	 * @var int
	 */
	protected  $id;

	/**
	 * @return int
	 */
	public function getId()
	{
		return $this->id;
	}

	/**
	 * @return string
	 */
	public function getName()
	{
		return $this->name;
	}

	/**
	 * @param string $name
	 * @return ExampleEntity
	 */
	public function setName($name)
	{
		$this->name = $name;
		return $this;
	}
	
	/**
	 * @param TestExampleEntityRel $related
	 * @return ExampleEntity
	 */
	public function setRelated(TestExampleEntityRel $related) 
	{
		$this->related = $related;
		return $this;
	}
	
	/**
	 * @return TestExampleEntityRel
	 */
	public function getRelated()
	{
		return $this->related;
	}
}

class ExampleFormMapper
{
	/** @var FormEntityBuilder */
	private $formEntityBuilder;

	/**
	 * ExampleFormMapper constructor.
	 * @param FormEntityBuilder $formEntityBuilder
	 */
	public function __construct(FormEntityBuilder $formEntityBuilder)
	{
		$this->formEntityBuilder = $formEntityBuilder;
	}


public function getForm() {
		$entity = new ExampleEntity();
		$entity->setName('Example name');

		// TRUE param build form automatically
		$builder = $this->formEntityBuilder->getBuilder($entity, TRUE);
		$form = $builder->getForm();

		$form->addSubmit('Sub', 'Save');

		$form->onSuccess[] = function(Form $form) {
			// do stuff
		};

		// FALSE param is manual render form
		$builder = $this->formEntityBuilder->getBuilder($entity, FALSE);

		$builder->add([
			'propertyName'  => 'name',
			// allowed types in BuilderDefinition::COMPONENT_TYPE_*
			'componentType' => BuilderDefinition::COMPONENT_TYPE_TEXT_AREA, // override component type (component type is generated automatically from entity)
			'settings' => [
				'label' => 'Name',
				'placeholder'   => 'example@example.com',
				'required'      => TRUE,
				'value'         => 'New name', // override value
				'values'        => ['key' => 'Value', 'key2' => 'Value 2'], // set possible values for list (CheckboxList, RadioList, SelectBox,...)
				'appendValidationRules' => [ // append validation rules
					[
						'validator' => Form::EMAIL,
						'text'      => 'Please fill valid email'
					]
				],
				'validationRules' => [ // replace validation rules
					[
						'validator' => Form::NUMERIC,
						'text'      => 'Please fill number'
					]
				],
			]
		]);

		// this create container with name related and edit box for name and hidden id value
		$builder->add([
			'propertyName'  => 'related',
			'componentType' => BuilderDefinition::COMPONENT_TYPE_CONTAINER,
			'settings' => [
				[
					'propertyName'  => 'name',
					'componentType' => BuilderDefinition::COMPONENT_TYPE_TEXT,
					'settings' => [
						'label' => 'Name'
					]
				],
				[
					'propertyName'  => 'id',
					'componentType' => BuilderDefinition::COMPONENT_TYPE_HIDDEN,
				]
			]
		]);

		return $form;
	}
}

表单构建器会自动从属性类型中建议类型。此构建器会自动建议必填和数值类型。自动从属性类型创建组件类型并查找关系。当您通过任何注释映射关系时,构建器会从 Kdyby 的 EntityManager 中查找值和键。目标实体必须指定 __toString 方法,因为它用于 select、radio 等标签。