arkschools / data-input-sheets
从脊类和yml配置文件构建数据表的库
Requires
- keyvanakbary/slugifier: ^4.0
- symfony/yaml: ~2.0|~3.0
Requires (Dev)
- doctrine/dbal: 2.5.x-dev
- doctrine/doctrine-bundle: ~1.2
- doctrine/orm: ~2.2,>=2.2.3,<2.5
- phpspec/phpspec: ^3.1
- phpunit/phpunit: ^5.6
- sensio/framework-extra-bundle: ^3.0
- symfony/config: ~2.4|~3.0
- symfony/dependency-injection: ~2.4|~3.0
- symfony/http-kernel: ~2.4|~3.0
- twig/twig: ~1.0
This package is not auto-updated.
Last update: 2024-09-24 23:28:24 UTC
README
库将自定义数据源抽象为表格的脊,并使用通过yml配置文件定义的列构建数据表。该库处理显示表格和存储用户输入值的逻辑。每一行都可以通过新页面访问,该页面将显示一个表格,其中每个对象列对应一行
说明
使用composer下载
composer require arkschools/data-input-sheets
在内核中启用捆绑
// app/AppKernel.php public function registerBundles() { $bundles = array( // ... new Arkschools\DataInputSheets\Bridge\Symfony\DataInputSheetsBundle(), // ... ); }
创建yml配置
# app/config/config.yml data_input_sheets: extra_column_types: color: AppBundle/DataInputSheets/ColumnType/Color sheets: cars: views: "Brand and model": columns: ["Brand name", "Model name", "Description", "Color"] "Performance": columns: ["Brand name", "Top speed", "Acceleration"] columns: "Brand name": string "Model name": string "Description": text "Top speed": integer "Acceleration": float "Color": color
extra_column_types
是一个可选部分,允许通过新的列类型扩展库- 为每个自定义数据源创建一个表
- 创建所需的所有视图,列可以属于多个视图
- 为表创建所有需要的列,并设置每个列的适当类型
高级yml配置
有时一个视图有太多的列,不能为每个脊值显示为表格,在这种情况下,视图可以声明如下
sheets: cars: views: "Brand and model": columns: - "Brand name" - "Model name" - { column: "Description", hide: true } - "Color"
当访问单个脊元素时,将显示所有列
可以通过配置锁定列以防止修改,这在您不希望用户修改某些列的时期非常有用
# app/config/config.yml data_input_sheets: sheets: cars: views: "Brand and model": columns: ["Brand name", "Model name", "Description"] columns: "Brand name": type: string read_only: true "Model name": string "Description": text
创建脊及其服务
这是最重要的文件,从中查询脊列数据,我们需要创建一个扩展自 Arkschools\DataInputSheets\Spine
的类,并添加我们的逻辑到 load
和 __construct
class CarsSpine extends Arkschools\DataInputSheets\Spine { private $carRepository; public function __construct(CarRepository $carRepository) { parent::__construct( 'Available Cars', [] ); $this->carRepository = $carRepository; } protected function load() { if (empty($this->spine)) { $this->spine = []; $cars = $this->carRepository->findAll(); foreach ($cars as $car) { $this->spine[$car->id()] = $car->getName(); } asort($this->spine); } return $this; } }
下一步是创建一个标记了我们的脊的有标签的服务,为此,添加标签 data_input_sheets.spine
以标记服务为数据输入表脊,并通过sheet
属性将其与配置的表链接
AppBundle\DataInputSheets\CarsSpine: tags: - { name: data_input_sheets.spine, sheet: cars }
更新您的数据库模式
php bin/console doctrine:schema:update --force
创建/重用控制器和视图
提供了一个基本控制器和模板,但我们建议根据项目需求构建自己的一个
如果您想使用默认的,只需添加以下路由配置
# app/config/routing.yml data_input_sheets: resource: "@DataInputSheetsBundle/Controller/DataInputSheetsController" type: annotation
可用的列类型
integer
- 使用输入html元素捕获数据
- 将输入值转换为整数并将其存储在数据库中作为整数
float
- 使用输入html元素捕获数据
- 将输入值转换为浮点数并将其存储在数据库中作为浮点数
string
- 使用输入html元素捕获数据
- 将输入值存储在数据库中作为字符串,将空字符串转换为null值
text
- 使用textarea html元素捕获数据
- 将输入值存储在数据库中作为字符串,将空字符串转换为null值
date
- 使用输入html元素捕获数据
- 将输入值存储在数据库中作为datetime对象,将空字符串或格式不正确的日期转换为null值
- 默认情况下,它使用PHP DateTime格式
d/m/Y H:i
并向用户显示提示DD/MM/YYYY
这些值可以通过配置更改,如下所示
- column: 'Manufacturing Date' type: 'date' option: ['d/m/Y', 'DD/MM/YYYY']
yes/no
- 使用带有选项 '' => '', Y' => yes 和 'N' => no 的选择元素
- 使用 '', 'Y' 或 'N' 值,将它们转换为null或布尔值,并将它们存储在数据库中为空或布尔值
gender
- 使用带有选项 '' => '', 'M' => M 和 'F' => F 的选择元素
- 使用 '', M' 或 'F' 值并将它们存储在数据库中为字符串或null
serviceList
- 需要使用包含数组的属性选项,第一个元素是服务名称,第二个元素是该服务的操作名称
- column: 'Car Design' type: 'serviceList' option: ['app.data_input_sheets.car_lists', 'getCarDesigns']
- 应存在一个名为
app.data_input_sheets.car_lists
的服务,其中包含一个名为getCarDesigns
的方法,该方法将返回一个包含允许值的数组
class CarLists { public function getCarDesigns() { return ['Coupé', 'Sedan', 'SUV', 'Crossover']; } }
- 使用 select 元素,从列表中添加选项,并在开始处添加一个空选项
- 将选定的值以字符串的形式存储在数据库中,将空字符串转换为 null
->methodName
methodName
可以是任何可以用于 PHP 对象方法名称的字符串- 要求
load
方法中的 Spine 将 spine 对象数组存储在spineObjects
属性中,并按 spineId 索引
protected function load() { if (null === $this->spine) { $this->spine = []; $this->spineObjects = []; foreach ($this->cars as $car) { $this->spine[$car->id] = $car->getModel(); $this->spineObjects[$car->id] = $car; } asort($this->spine); } return $this; }
- Spine 对象应有一个名为
methodName
的方法,并且可以通过option
属性可选地传递给该方法参数
- column: 'Car length' type: '->getLength' option: ['meters']
- 仅用于显示值,不会在数据库中存储任何内容
高级用法
默认情况下,此库允许用户将数据存储在由库创建的表中,但此行为可以更改
未存储在默认实体管理器中
可以通过在 parameters.yml
文件中添加参数来设置不同的实体管理器
data_input_sheets.entity_manager_name: data
存储在库用户控制表中
可以将自定义表设置为存储特定工作表的数据输入
创建一个与 data_input_sheets_cell
相同结构的表,例如称为 'cars',并相应地修改 spine
class CarsSpine extends Arkschools\DataInputSheets\Spine { private $carRepository; public function __construct(CarRepository $carRepository) { parent::__construct( 'Available Cars', [], 'cars' ); $this->carRepository = $carRepository; } ...
从现在起,该工作表数据将存储在自定义表中
存储在库用户控制实体中
可以通过设置一个实体类来获得更多控制,该实体类将存储特定工作表的数据
创建所需的实体类,包含工作表所需的列数属性,例如需要 id
、brand
、model
和 description
,请考虑设置实体属性类型时列的类型
然后相应地修改 spine 类
class CarsSpine extends Arkschools\DataInputSheets\Spine { private $carRepository; public function __construct(CarRepository $carRepository) { parent::__construct( 'Available Cars', [], null AppBundle\Entity\Car::class, 'id' ); $this->carRepository = $carRepository; } ...
对于上一个示例,这将应该是新的配置文件内容
# app/config/config.yml data_input_sheets: sheets: cars: views: "Brand and model": ["Brand name", "Model name", "Description"] columns: "Brand name": type: string field: brand "Model name": type: string field: model "Description": type: text field: description
创建自定义列类型
如上所述,可以通过配置参数 extra_column_types
添加新列
- 扩展
Column
抽象类并实现抽象方法 - 根据需要扩展其他方法
- 使用
extra_column_types
配置添加新创建的类
将自定义列类型作为服务创建
AppBundle\DataInputSheets\ColumnState: tags: - { name: data_input_sheets.column, type: state }
- 标签
data_input_sheets.column
标记服务为数据输入表额外列,type
属性将其与新增的列类型链接 - 列类必须扩展
Arkschools\DataInputSheets\ColumnType\AbstractColumn
并添加至少__construct
的逻辑
在视图级别过滤 spine
可以在每个视图中添加过滤器,以限制在该视图中显示的 spine 元素
sheets: cars: views: "Classics": filters: {age: '>25'} columns: ["Brand name", "Model name", "Description", "Color"]
在上一个示例中,“Classics” 视图将仅显示 25 年以上的汽车,为了实现这一点,我们需要修改 spine 类以具有默认过滤器并使用它进行加载
class CarsSpine extends Arkschools\DataInputSheets\Spine { private $carRepository; public function __construct(CarRepository $carRepository) { parent::__construct( 'Available Cars', [] ); $this->carRepository = $carRepository; } protected function defaultFilter() { return ['age' => null]; } protected function load() { if (empty($this->spine) || $this->filtersChanged) { $this->spine = []; if (empty($this->filters['age']) { $cars = $this->carRepository->findAll(); else { $cars = $this->carRepository->findByAge($this->filters['age']); } foreach ($cars as $car) { $this->spine[$car->id()] = $car->getName(); } $this->filtersChanged = false; asort($this->spine); } return $this; } }
通过用户选择过滤 spine
除了可以在配置文件视图级别添加的过滤器外,还可以在选择视图并在显示其内容之前添加自定义选择器。此选择器可用于进一步缩小在视图中显示的 spine 元素。
正如我们之前看到的,一个Spine
可以通过扩展defaultFilter
方法来添加一个配置级别的过滤器,以及通过load
方法来使用它。这个新过滤器背后的想法是将用户选择过滤器添加到这个地方。
为了实现这一点,我们需要创建一个新的类,它继承自Arkschools\DataInputSheets\Selector\AbstractSelector
class DealerSelector extends Arkschools\DataInputSheets\Selector\AbstractSelector { const DEALER = 'dealer'; private $dealerRepository; public function __construct(DealerRepository $dealerRepository) { $this->dealerRepository = $dealerRepository; $this->filters = [self::DEALER => null]; } public function render(\Twig_Environment $twig, array $filters): string { // $filters contains filters that are declared in the spine, like age in the previous example $dealers = $this->dealerRepository->findAll(); return $twig->render( 'AppBundle:selector:dealer_selector.html.twig', ['dealers' => $dealers] ); } public function applyFilters(Request $request): bool { $dealer = $request->query->get(self::DEALER); $changed = false; if ($this->filters[self::DEALER] !== $dealer) { $this->filters[self::DEALER] = $dealer; $changed = true; } return $changed; } public function isRequired(): bool { return empty($this->filters[self::DEALER]); } }
然后添加一个带有data_input_sheets.selector
标签的selector服务,以及将在配置中使用的类型
AppBundle\DataInputSheets\DealerSelector: tags: - { name: data_input_sheets.selector, type: dealer }
下一步是创建一个Twig模板来显示这个选择器,它应该像这样
<form name="selector" method="get"> <label for="{{ constant('AppBundle\\DataInputSheets\\DealerSelector::DEALER') }}">Dealer:</label> <select class="form-control" name="{{ constant('AppBundle\\DataInputSheets\\DealerSelector::DEALER') }}"> <option value="">Dealers:</option> {% for dealer in dealers %} <option value="{{ dealer.code }}">{{ dealer.name }}</option> {% endfor %} </select> <button type="submit" class="btn btn-primary">Continue</button> </form>
最后,修改表单配置文件以使用新的选择器
# app/config/config.yml data_input_sheets: sheets: cars: selector: 'dealer' views: "Brand and model": columns: ["Brand name", "Model name", "Description"] columns: "Brand name": string "Model name": string "Description": text