├── .gitignore ├── README.md ├── TreeColumn.php ├── TreeGrid.php ├── TreeGridAsset.php ├── composer.json └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # phpstorm project files 2 | .idea 3 | 4 | # netbeans project files 5 | nbproject 6 | 7 | # zend studio for eclipse project files 8 | .buildpath 9 | .project 10 | .settings 11 | 12 | # windows thumbnail cache 13 | Thumbs.db 14 | 15 | # composer vendor dir 16 | /vendor 17 | 18 | # composer itself is not needed 19 | composer.phar 20 | 21 | # Mac DS_Store Files 22 | .DS_Store 23 | 24 | # phpunit itself is not needed 25 | phpunit.phar 26 | # local phpunit config 27 | /phpunit.xml 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery TreeGrid Extension for Yii 2 2 | 3 | This is the [jQuery TreeGrid](https://github.com/maxazan/jquery-treegrid) extension for Yii 2. It encapsulates TreeGrid component in terms of Yii widgets, 4 | and thus makes using TreeGrid component in Yii applications extremely easy 5 | 6 | [![Yii2](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](http://www.yiiframework.com/) 7 | [![Latest Stable Version](https://poser.pugx.org/leandrogehlen/yii2-treegrid/v/stable.png)](https://packagist.org/packages/leandrogehlen/yii2-treegrid) 8 | [![Total Downloads](https://poser.pugx.org/leandrogehlen/yii2-treegrid/downloads.png)](https://packagist.org/packages/leandrogehlen/yii2-treegrid) 9 | 10 | ## Installation 11 | 12 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 13 | 14 | Either run 15 | 16 | ``` 17 | php composer.phar require --prefer-dist leandrogehlen/yii2-treegrid "*" 18 | ``` 19 | 20 | or add 21 | 22 | ``` 23 | "leandrogehlen/yii2-treegrid": "*" 24 | ``` 25 | 26 | to the require section of your `composer.json` file. 27 | 28 | ## Usage 29 | 30 | **Model** 31 | 32 | ```php 33 | 34 | use yii\db\ActiveRecord; 35 | 36 | /** 37 | * @property string $description 38 | * @property integer $parent_id 39 | */ 40 | class Tree extends ActiveRecord 41 | { 42 | 43 | /** 44 | * @inheritdoc 45 | */ 46 | public static function tableName() 47 | { 48 | return 'tree'; 49 | } 50 | 51 | /** 52 | * @inheritdoc 53 | */ 54 | public function rules() 55 | { 56 | return [ 57 | [['description'], 'required'], 58 | [['description'], 'string'], 59 | [['parent_id'], 'integer'] 60 | ]; 61 | } 62 | } 63 | ``` 64 | 65 | **Controller** 66 | 67 | ```php 68 | use yii\web\Controller; 69 | use Yii; 70 | use yii\data\ActiveDataProvider; 71 | 72 | class TreeController extends Controller 73 | { 74 | 75 | /** 76 | * Lists all Tree models. 77 | * @return mixed 78 | */ 79 | public function actionIndex() 80 | { 81 | $query = Tree::find(); 82 | $dataProvider = new ActiveDataProvider([ 83 | 'query' => $query, 84 | 'pagination' => false 85 | ]); 86 | 87 | return $this->render('index', [ 88 | 'dataProvider' => $dataProvider 89 | ]); 90 | } 91 | ``` 92 | 93 | **View** 94 | 95 | ```php 96 | use leandrogehlen\treegrid\TreeGrid; 97 | 98 | $dataProvider, 100 | 'keyColumnName' => 'id', 101 | 'parentColumnName' => 'parent_id', 102 | 'parentRootValue' => '0', //first parentId value 103 | 'pluginOptions' => [ 104 | 'initialState' => 'collapsed', 105 | ], 106 | 'columns' => [ 107 | 'name', 108 | 'id', 109 | 'parent_id', 110 | ['class' => 'yii\grid\ActionColumn'] 111 | ] 112 | ]); ?> 113 | ``` 114 | 115 | ## Adding resources 116 | 117 | When is necessary to add other resource files, then should be used the [Dependency Injection](http://www.yiiframework.com/doc-2.0/guide-concept-di-container.html#registering-dependencies) concept. 118 | 119 | To use the `saveState` option it's necessary to add `jquery.cookie.js`. 120 | 121 | ```php 122 | //config/web.php 123 | 124 | $config = [ 125 | 'id' => 'my-app', 126 | 'components' => [ 127 | ... 128 | ] 129 | ... 130 | ] 131 | 132 | Yii::$container->set('leandrogehlen\treegrid\TreeGridAsset',[ 133 | 'js' => [ 134 | 'js/jquery.cookie.js', 135 | 'js/jquery.treegrid.min.js', 136 | ] 137 | ]); 138 | 139 | return $config; 140 | ``` 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /TreeColumn.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | class TreeColumn extends BaseObject 21 | { 22 | /** 23 | * @var TreeGrid the grid view object that owns this column. 24 | */ 25 | public $grid; 26 | 27 | /** 28 | * @var string the header cell content. Note that it will not be HTML-encoded. 29 | */ 30 | public $header; 31 | 32 | /** 33 | * @var string the footer cell content. Note that it will not be HTML-encoded. 34 | */ 35 | public $footer; 36 | 37 | /** 38 | * @var callable This is a callable that will be used to generate the content of each cell. 39 | * The signature of the function should be the following: `function ($model, $key, $index, $column)`. 40 | * Where `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being rendered 41 | * and `$column` is a reference to the [[TreeColumn]] object. 42 | */ 43 | public $content; 44 | 45 | /** 46 | * @var bool whether this column is visible. Defaults to true. 47 | */ 48 | public $visible = true; 49 | 50 | /** 51 | * @var array the HTML attributes for the column group tag. 52 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 53 | */ 54 | public $options = []; 55 | 56 | /** 57 | * @var array the HTML attributes for the header cell tag. 58 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 59 | */ 60 | public $headerOptions = []; 61 | 62 | /** 63 | * @var array|\Closure the HTML attributes for the data cell tag. This can either be an array of 64 | * attributes or an anonymous function ([[Closure]]) that returns such an array. 65 | * The signature of the function should be the following: `function ($model, $key, $index, $column)`. 66 | * Where `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being rendered 67 | * and `$column` is a reference to the [[Column]] object. 68 | * A function may be used to assign different attributes to different rows based on the data in that row. 69 | * 70 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 71 | */ 72 | public $contentOptions = []; 73 | 74 | /** 75 | * @var array the HTML attributes for the footer cell tag. 76 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 77 | */ 78 | public $footerOptions = []; 79 | 80 | /** 81 | * @var string the attribute name associated with this column. When neither [[content]] nor [[value]] 82 | * is specified, the value of the specified attribute will be retrieved from each data model and displayed. 83 | * 84 | * Also, if [[label]] is not specified, the label associated with the attribute will be displayed. 85 | */ 86 | public $attribute; 87 | 88 | /** 89 | * @var string label to be displayed in the [[header|header cell]] and also to be used as the sorting 90 | * link label when sorting is enabled for this column. 91 | * If it is not set and the models provided by the GridViews data provider are instances 92 | * of [[\yii\db\ActiveRecord]], the label will be determined using [[\yii\db\ActiveRecord::getAttributeLabel()]]. 93 | * Otherwise [[\yii\helpers\Inflector::camel2words()]] will be used to get a label. 94 | */ 95 | public $label; 96 | 97 | /** 98 | * @var bool whether the header label should be HTML-encoded. 99 | * @see label 100 | */ 101 | public $encodeLabel = true; 102 | 103 | /** 104 | * @var string|\Closure an anonymous function or a string that is used to determine the value to display in the current column. 105 | * 106 | * If this is an anonymous function, it will be called for each row and the return value will be used as the value to 107 | * display for every data model. The signature of this function should be: `function ($model, $key, $index, $column)`. 108 | * Where `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being rendered 109 | * and `$column` is a reference to the [[DataColumn]] object. 110 | * 111 | * You may also set this property to a string representing the attribute name to be displayed in this column. 112 | * This can be used when the attribute to be displayed is different from the [[attribute]] that is used for 113 | * sorting and filtering. 114 | * 115 | * If this is not set, `$model[$attribute]` will be used to obtain the value, where `$attribute` is the value of [[attribute]]. 116 | */ 117 | public $value; 118 | 119 | /** 120 | * @var string|array in which format should the value of each data model be displayed as (e.g. `"raw"`, `"text"`, `"html"`, 121 | * `['date', 'php:Y-m-d']`). Supported formats are determined by the [[GridView::formatter|formatter]] used by 122 | * the [[GridView]]. Default format is "text" which will format the value as an HTML-encoded plain text when 123 | * [[\yii\i18n\Formatter]] is used as the [[GridView::$formatter|formatter]] of the GridView. 124 | */ 125 | public $format = 'text'; 126 | 127 | /** 128 | * Renders the header cell. 129 | */ 130 | public function renderHeaderCell() 131 | { 132 | return Html::tag('th', $this->renderHeaderCellContent(), $this->headerOptions); 133 | } 134 | 135 | /** 136 | * Renders the footer cell. 137 | */ 138 | public function renderFooterCell() 139 | { 140 | return Html::tag('td', $this->renderFooterCellContent(), $this->footerOptions); 141 | } 142 | 143 | /** 144 | * Renders a data cell. 145 | * @param mixed $model the data model being rendered 146 | * @param mixed $key the key associated with the data model 147 | * @param int $index the zero-based index of the data item among the item array returned by [[GridView::dataProvider]]. 148 | * @return string the rendering result 149 | */ 150 | public function renderDataCell($model, $key, $index) 151 | { 152 | if ($this->contentOptions instanceof Closure) { 153 | $options = call_user_func($this->contentOptions, $model, $key, $index, $this); 154 | } else { 155 | $options = $this->contentOptions; 156 | } 157 | return Html::tag('td', $this->renderDataCellContent($model, $key, $index), $options); 158 | } 159 | 160 | /** 161 | * Renders the header cell content. 162 | * The default implementation simply renders [[header]]. 163 | * This method may be overridden to customize the rendering of the header cell. 164 | * @return string the rendering result 165 | */ 166 | protected function renderHeaderCellContent() 167 | { 168 | if ($this->header !== null || $this->label === null && $this->attribute === null) { 169 | return trim($this->header) !== '' ? $this->header : $this->grid->emptyCell; 170 | } 171 | 172 | $provider = $this->grid->dataProvider; 173 | 174 | if ($this->label === null) { 175 | if ($provider instanceof ActiveDataProvider && $provider->query instanceof ActiveQueryInterface) { 176 | /* @var $model Model */ 177 | $model = new $provider->query->modelClass; 178 | $label = $model->getAttributeLabel($this->attribute); 179 | } else { 180 | $models = $provider->getModels(); 181 | if (($model = reset($models)) instanceof Model) { 182 | /* @var $model Model */ 183 | $label = $model->getAttributeLabel($this->attribute); 184 | } else { 185 | $label = Inflector::camel2words($this->attribute); 186 | } 187 | } 188 | } else { 189 | $label = $this->label; 190 | } 191 | 192 | return $this->encodeLabel ? Html::encode($label) : $label; 193 | } 194 | 195 | /** 196 | * Renders the footer cell content. 197 | * The default implementation simply renders [[footer]]. 198 | * This method may be overridden to customize the rendering of the footer cell. 199 | * @return string the rendering result 200 | */ 201 | protected function renderFooterCellContent() 202 | { 203 | return trim($this->footer) !== '' ? $this->footer : $this->grid->emptyCell; 204 | } 205 | 206 | /** 207 | * Renders the data cell content. 208 | * @param mixed $model the data model 209 | * @param mixed $key the key associated with the data model 210 | * @param int $index the zero-based index of the data model among the models array returned by [[GridView::dataProvider]]. 211 | * @return string the rendering result 212 | */ 213 | protected function renderDataCellContent($model, $key, $index) 214 | { 215 | if ($this->content === null) { 216 | return $this->grid->formatter->format($this->getDataCellValue($model, $key, $index), $this->format); 217 | } else { 218 | if ($this->content !== null) { 219 | return call_user_func($this->content, $model, $key, $index, $this); 220 | } else { 221 | return $this->grid->emptyCell; 222 | } 223 | } 224 | } 225 | 226 | /** 227 | * Returns the data cell value. 228 | * @param mixed $model the data model 229 | * @param mixed $key the key associated with the data model 230 | * @param int $index the zero-based index of the data model among the models array returned by [[GridView::dataProvider]]. 231 | * @return string the data cell value 232 | */ 233 | public function getDataCellValue($model, $key, $index) 234 | { 235 | if ($this->value !== null) { 236 | if (is_string($this->value)) { 237 | return ArrayHelper::getValue($model, $this->value); 238 | } else { 239 | return call_user_func($this->value, $model, $key, $index, $this); 240 | } 241 | } elseif ($this->attribute !== null) { 242 | return ArrayHelper::getValue($model, $this->attribute); 243 | } 244 | return null; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /TreeGrid.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | class TreeGrid extends Widget 23 | { 24 | /** 25 | * @var \yii\data\DataProviderInterface|\yii\data\BaseDataProvider the data provider for the view. This property is required. 26 | */ 27 | public $dataProvider; 28 | 29 | /** 30 | * @var string the default data column class if the class name is not explicitly specified when configuring a data column. 31 | * Defaults to 'leandrogehlen\treegrid\TreeColumn'. 32 | */ 33 | public $dataColumnClass; 34 | 35 | /** 36 | * @var array the HTML attributes for the container tag of the grid view. 37 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 38 | */ 39 | public $options = ['class' => 'table table-striped table-bordered']; 40 | 41 | /** 42 | * @var array The plugin options 43 | */ 44 | public $pluginOptions = []; 45 | 46 | /** 47 | * @var array the HTML attributes for the table header row. 48 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 49 | */ 50 | public $headerRowOptions = []; 51 | /** 52 | * @var array the HTML attributes for the table footer row. 53 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 54 | */ 55 | public $footerRowOptions = []; 56 | 57 | /** 58 | * @var string the HTML display when the content of a cell is empty 59 | */ 60 | public $emptyCell = ' '; 61 | 62 | /** 63 | * @var string the HTML content to be displayed when [[dataProvider]] does not have any data. 64 | */ 65 | public $emptyText; 66 | 67 | /** 68 | * @var array the HTML attributes for the emptyText of the list view. 69 | * The "tag" element specifies the tag name of the emptyText element and defaults to "div". 70 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 71 | */ 72 | public $emptyTextOptions = ['class' => 'empty']; 73 | 74 | /** 75 | * @var bool whether to show the header section of the grid table. 76 | */ 77 | public $showHeader = true; 78 | /** 79 | * @var bool whether to show the footer section of the grid table. 80 | */ 81 | public $showFooter = false; 82 | /** 83 | * @var bool whether to show the grid view if [[dataProvider]] returns no data. 84 | */ 85 | public $showOnEmpty = true; 86 | 87 | /** 88 | * @var array|Formatter the formatter used to format model attribute values into displayable texts. 89 | * This can be either an instance of [[Formatter]] or an configuration array for creating the [[Formatter]] 90 | * instance. If this property is not set, the "formatter" application component will be used. 91 | */ 92 | public $formatter; 93 | 94 | /** 95 | * @var array|Closure the HTML attributes for the table body rows. This can be either an array 96 | * specifying the common HTML attributes for all body rows, or an anonymous function that 97 | * returns an array of the HTML attributes. The anonymous function will be called once for every 98 | * data model returned by [[dataProvider]]. It should have the following signature: 99 | * 100 | * ```php 101 | * function ($model, $key, $index, $grid) 102 | * ``` 103 | * 104 | * - `$model`: the current data model being rendered 105 | * - `$key`: the key value associated with the current data model 106 | * - `$index`: the zero-based index of the data model in the model array returned by [[dataProvider]] 107 | * - `$grid`: the GridView object 108 | * 109 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 110 | */ 111 | public $rowOptions = []; 112 | 113 | /** 114 | * @var Closure an anonymous function that is called once BEFORE rendering each data model. 115 | * It should have the similar signature as [[rowOptions]]. The return result of the function 116 | * will be rendered directly. 117 | */ 118 | public $beforeRow; 119 | 120 | /** 121 | * @var Closure an anonymous function that is called once AFTER rendering each data model. 122 | * It should have the similar signature as [[rowOptions]]. The return result of the function 123 | * will be rendered directly. 124 | */ 125 | public $afterRow; 126 | 127 | /** 128 | * @var string name of key column used to build tree 129 | */ 130 | public $keyColumnName; 131 | 132 | /** 133 | * @var string name of parent column used to build tree 134 | */ 135 | public $parentColumnName; 136 | 137 | /** 138 | * @var mixed parent column value of root elements from data 139 | */ 140 | public $parentRootValue = null; 141 | 142 | /** 143 | * @var array grid column configuration. Each array element represents the configuration 144 | * for one particular grid column. 145 | * @see \yii\grid::$columns for details. 146 | */ 147 | public $columns = []; 148 | /** 149 | * Initializes the grid view. 150 | * This method will initialize required property values and instantiate [[columns]] objects. 151 | */ 152 | public function init() 153 | { 154 | if ($this->dataProvider === null) { 155 | throw new InvalidConfigException('The "dataProvider" property must be set.'); 156 | } 157 | if ($this->emptyText === null) { 158 | $this->emptyText = Yii::t('yii', 'No results found.'); 159 | } 160 | if (!isset($this->options['id'])) { 161 | $this->options['id'] = $this->getId(); 162 | } 163 | 164 | if ($this->formatter == null) { 165 | $this->formatter = Yii::$app->getFormatter(); 166 | } elseif (is_array($this->formatter)) { 167 | $this->formatter = Yii::createObject($this->formatter); 168 | } 169 | if (!$this->formatter instanceof Formatter) { 170 | throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.'); 171 | } 172 | 173 | if (!$this->keyColumnName) { 174 | throw new InvalidConfigException('The "keyColumnName" property must be specified"'); 175 | } 176 | if (!$this->parentColumnName) { 177 | throw new InvalidConfigException('The "parentColumnName" property must be specified"'); 178 | } 179 | 180 | $this->initColumns(); 181 | } 182 | 183 | /** 184 | * Runs the widget. 185 | */ 186 | public function run() 187 | { 188 | $id = $this->options['id']; 189 | $options = Json::htmlEncode($this->pluginOptions); 190 | 191 | $view = $this->getView(); 192 | TreeGridAsset::register($view); 193 | 194 | $view->registerJs("jQuery('#$id').treegrid($options);"); 195 | 196 | if ($this->showOnEmpty || $this->dataProvider->getCount() > 0) { 197 | $header = $this->showHeader ? $this->renderTableHeader() : false; 198 | $body = $this->renderItems(); 199 | $footer = $this->showFooter ? $this->renderTableFooter() : false; 200 | 201 | $content = array_filter([ 202 | $header, 203 | $body, 204 | $footer 205 | ]); 206 | 207 | return Html::tag('table', implode("\n", $content), $this->options); 208 | } else { 209 | return $this->renderEmpty(); 210 | } 211 | } 212 | 213 | /** 214 | * Renders the HTML content indicating that the list view has no data. 215 | * @return string the rendering result 216 | * @see emptyText 217 | */ 218 | public function renderEmpty() 219 | { 220 | $options = $this->emptyTextOptions; 221 | $tag = ArrayHelper::remove($options, 'tag', 'div'); 222 | return Html::tag($tag, ($this->emptyText === null ? Yii::t('yii', 'No results found.') : $this->emptyText), $options); 223 | } 224 | 225 | /** 226 | * Renders a table row with the given data model and key. 227 | * @param mixed $model the data model to be rendered 228 | * @param mixed $key the key associated with the data model 229 | * @param integer $index the zero-based index of the data model among the model array returned by [[dataProvider]]. 230 | * @return string the rendering result 231 | */ 232 | public function renderTableRow($model, $key, $index) 233 | { 234 | $cells = []; 235 | /* @var $column TreeColumn */ 236 | foreach ($this->columns as $column) { 237 | $cells[] = $column->renderDataCell($model, $key, $index); 238 | } 239 | if ($this->rowOptions instanceof Closure) { 240 | $options = call_user_func($this->rowOptions, $model, $key, $index, $this); 241 | } else { 242 | $options = $this->rowOptions; 243 | } 244 | $options['data-key'] = is_array($key) ? json_encode($key) : (string) $key; 245 | 246 | $id = ArrayHelper::getValue($model, $this->keyColumnName); 247 | Html::addCssClass($options, "treegrid-$id"); 248 | 249 | $parentId = ArrayHelper::getValue($model, $this->parentColumnName); 250 | if ($parentId) { 251 | if(ArrayHelper::getValue($this->pluginOptions, 'initialState') == 'collapsed'){ 252 | Html::addCssStyle($options, 'display: none;'); 253 | } 254 | Html::addCssClass($options, "treegrid-parent-$parentId"); 255 | } 256 | 257 | return Html::tag('tr', implode('', $cells), $options); 258 | } 259 | 260 | /** 261 | * Renders the table header. 262 | * @return string the rendering result. 263 | */ 264 | public function renderTableHeader() 265 | { 266 | $cells = []; 267 | foreach ($this->columns as $column) { 268 | /* @var $column TreeColumn */ 269 | $cells[] = $column->renderHeaderCell(); 270 | } 271 | $content = Html::tag('tr', implode('', $cells), $this->headerRowOptions); 272 | return "\n" . $content . "\n"; 273 | } 274 | 275 | /** 276 | * Renders the table footer. 277 | * @return string the rendering result. 278 | */ 279 | public function renderTableFooter() 280 | { 281 | $cells = []; 282 | foreach ($this->columns as $column) { 283 | /* @var $column TreeColumn */ 284 | $cells[] = $column->renderFooterCell(); 285 | } 286 | $content = Html::tag('tr', implode('', $cells), $this->footerRowOptions); 287 | return "\n" . $content . "\n"; 288 | } 289 | 290 | /** 291 | * Renders the data models for the grid view. 292 | */ 293 | public function renderItems() 294 | { 295 | $rows = []; 296 | $this->dataProvider->setKeys([]); 297 | $models = array_values($this->dataProvider->getModels()); 298 | $models = $this->normalizeData($models, $this->parentRootValue); 299 | $this->dataProvider->setModels($models); 300 | $this->dataProvider->setKeys(null); 301 | $this->dataProvider->prepare(); 302 | $keys = $this->dataProvider->getKeys(); 303 | foreach ($models as $index => $model) { 304 | $key = $keys[$index]; 305 | if ($this->beforeRow !== null) { 306 | $row = call_user_func($this->beforeRow, $model, $key, $index, $this); 307 | if (!empty($row)) { 308 | $rows[] = $row; 309 | } 310 | } 311 | 312 | $rows[] = $this->renderTableRow($model, $key, $index); 313 | 314 | if ($this->afterRow !== null) { 315 | $row = call_user_func($this->afterRow, $model, $key, $index, $this); 316 | if (!empty($row)) { 317 | $rows[] = $row; 318 | } 319 | } 320 | } 321 | 322 | if (empty($rows)) { 323 | $colspan = count($this->columns); 324 | return "" . $this->renderEmpty() . ""; 325 | } else { 326 | return implode("\n", $rows); 327 | } 328 | } 329 | 330 | /** 331 | * Creates column objects and initializes them. 332 | */ 333 | protected function initColumns() 334 | { 335 | if (empty($this->columns)) { 336 | $this->guessColumns(); 337 | } 338 | foreach ($this->columns as $i => $column) { 339 | if (is_string($column)) { 340 | $column = $this->createDataColumn($column); 341 | } else { 342 | $column = Yii::createObject(array_merge([ 343 | 'class' => $this->dataColumnClass ? : TreeColumn::className(), 344 | 'grid' => $this, 345 | ], $column)); 346 | } 347 | if (!$column->visible) { 348 | unset($this->columns[$i]); 349 | continue; 350 | } 351 | $this->columns[$i] = $column; 352 | } 353 | } 354 | 355 | /** 356 | * Creates a [[DataColumn]] object based on a string in the format of "attribute:format:label". 357 | * @param string $text the column specification string 358 | * @return DataColumn the column instance 359 | * @throws InvalidConfigException if the column specification is invalid 360 | */ 361 | protected function createDataColumn($text) 362 | { 363 | if (!preg_match('/^([^:]+)(:(\w*))?(:(.*))?$/', $text, $matches)) { 364 | throw new InvalidConfigException('The column must be specified in the format of "attribute", "attribute:format" or "attribute:format:label"'); 365 | } 366 | 367 | return Yii::createObject([ 368 | 'class' => $this->dataColumnClass ? : TreeColumn::className(), 369 | 'grid' => $this, 370 | 'attribute' => $matches[1], 371 | 'format' => isset($matches[3]) ? $matches[3] : 'text', 372 | 'label' => isset($matches[5]) ? $matches[5] : null, 373 | ]); 374 | } 375 | 376 | /** 377 | * This function tries to guess the columns to show from the given data 378 | * if [[columns]] are not explicitly specified. 379 | */ 380 | protected function guessColumns() 381 | { 382 | $models = $this->dataProvider->getModels(); 383 | $model = reset($models); 384 | if (is_array($model) || is_object($model)) { 385 | foreach ($model as $name => $value) { 386 | $this->columns[] = $name; 387 | } 388 | } 389 | } 390 | 391 | /** 392 | * Normalize tree data 393 | * @param array $data 394 | * @param string $parentId 395 | * @return array 396 | */ 397 | protected function normalizeData(array $data, $parentId = null) { 398 | $result = []; 399 | foreach ($data as $element) { 400 | if (ArrayHelper::getValue($element, $this->parentColumnName) == $parentId) { 401 | $result[] = $element; 402 | $children = $this->normalizeData($data, ArrayHelper::getValue($element, $this->keyColumnName)); 403 | if ($children) { 404 | $result = array_merge($result, $children); 405 | } 406 | } 407 | } 408 | return $result; 409 | } 410 | } 411 | -------------------------------------------------------------------------------- /TreeGridAsset.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class TreeGridAsset extends AssetBundle { 13 | 14 | public $sourcePath = '@bower/jquery-treegrid'; 15 | 16 | public $js = [ 17 | 'js/jquery.treegrid.min.js', 18 | ]; 19 | 20 | public $css = [ 21 | 'css/jquery.treegrid.css', 22 | ]; 23 | 24 | public $depends = [ 25 | 'yii\web\JqueryAsset' 26 | ]; 27 | 28 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leandrogehlen/yii2-treegrid", 3 | "description": "Extension for Yii2 Framework to work with jQuery TreeGrid", 4 | "keywords": ["yii2", "tree", "treeview", "treegrid", "interface"], 5 | "type": "yii2-extension", 6 | "license": "BSD-3-Clause", 7 | "support": { 8 | "issues": "https://github.com/leandrogehlen/yii2-treegrid/issues", 9 | "source": "https://github.com/leandrogehlen/yii2-treegrid" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Leandro Guindani Gehlen", 14 | "email": "leandrogehlen@gmail.com" 15 | } 16 | ], 17 | "require": { 18 | "yiisoft/yii2": "~2.0.13", 19 | "bower-asset/jquery-treegrid": "0.3.0" 20 | }, 21 | "require-dev": { 22 | "phpunit/phpunit": "3.7.*" 23 | }, 24 | "autoload": { 25 | "psr-4": { "leandrogehlen\\treegrid\\": "" } 26 | }, 27 | "extra": { 28 | "branch-alias": { 29 | "dev-master": "1.0.x-dev" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "7ff1235f9821ce2739dc8cd9299a4773", 8 | "packages": [ 9 | { 10 | "name": "bower-asset/inputmask", 11 | "version": "3.3.11", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/RobinHerbots/Inputmask.git", 15 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/5e670ad62f50c738388d4dcec78d2888505ad77b", 20 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "bower-asset/jquery": ">=1.7" 25 | }, 26 | "type": "bower-asset-library", 27 | "extra": { 28 | "bower-asset-main": [ 29 | "./dist/inputmask/inputmask.js", 30 | "./dist/inputmask/inputmask.extensions.js", 31 | "./dist/inputmask/inputmask.date.extensions.js", 32 | "./dist/inputmask/inputmask.numeric.extensions.js", 33 | "./dist/inputmask/inputmask.phone.extensions.js", 34 | "./dist/inputmask/jquery.inputmask.js", 35 | "./dist/inputmask/global/document.js", 36 | "./dist/inputmask/global/window.js", 37 | "./dist/inputmask/phone-codes/phone.js", 38 | "./dist/inputmask/phone-codes/phone-be.js", 39 | "./dist/inputmask/phone-codes/phone-nl.js", 40 | "./dist/inputmask/phone-codes/phone-ru.js", 41 | "./dist/inputmask/phone-codes/phone-uk.js", 42 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jqlite.js", 43 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jquery.js", 44 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.js", 45 | "./dist/inputmask/bindings/inputmask.binding.js" 46 | ], 47 | "bower-asset-ignore": [ 48 | "**/*", 49 | "!dist/*", 50 | "!dist/inputmask/*", 51 | "!dist/min/*", 52 | "!dist/min/inputmask/*" 53 | ] 54 | }, 55 | "license": [ 56 | "http://opensource.org/licenses/mit-license.php" 57 | ], 58 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.", 59 | "keywords": [ 60 | "form", 61 | "input", 62 | "inputmask", 63 | "jquery", 64 | "mask", 65 | "plugins" 66 | ], 67 | "time": "2017-11-21T11:46:23+00:00" 68 | }, 69 | { 70 | "name": "bower-asset/jquery", 71 | "version": "3.2.1", 72 | "source": { 73 | "type": "git", 74 | "url": "https://github.com/jquery/jquery-dist.git", 75 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e" 76 | }, 77 | "dist": { 78 | "type": "zip", 79 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/77d2a51d0520d2ee44173afdf4e40a9201f5964e", 80 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e", 81 | "shasum": "" 82 | }, 83 | "type": "bower-asset-library", 84 | "extra": { 85 | "bower-asset-main": "dist/jquery.js", 86 | "bower-asset-ignore": [ 87 | "package.json" 88 | ] 89 | }, 90 | "license": [ 91 | "MIT" 92 | ], 93 | "keywords": [ 94 | "browser", 95 | "javascript", 96 | "jquery", 97 | "library" 98 | ], 99 | "time": "2017-03-20T19:02:00+00:00" 100 | }, 101 | { 102 | "name": "bower-asset/jquery-treegrid", 103 | "version": "0.3.0", 104 | "source": { 105 | "type": "git", 106 | "url": "https://github.com/maxazan/jquery-treegrid.git", 107 | "reference": "c8ba9e9604620002155d01a947cceffe18d4428c" 108 | }, 109 | "dist": { 110 | "type": "zip", 111 | "url": "https://api.github.com/repos/maxazan/jquery-treegrid/zipball/c8ba9e9604620002155d01a947cceffe18d4428c", 112 | "reference": "c8ba9e9604620002155d01a947cceffe18d4428c", 113 | "shasum": "" 114 | }, 115 | "require": { 116 | "bower-asset/jquery": ">=1.9.1", 117 | "bower-asset/jquery.cookie": ">=1.4.1" 118 | }, 119 | "type": "bower-asset-library", 120 | "extra": { 121 | "bower-asset-ignore": [ 122 | "examples", 123 | "tests", 124 | "**/.*", 125 | "composer.json", 126 | "index.html", 127 | "params.json", 128 | "style.css", 129 | "test.html", 130 | "treegrid.jquery.json" 131 | ] 132 | }, 133 | "license": [ 134 | "MIT" 135 | ], 136 | "description": "TreeGrid plugin for jQuery.", 137 | "keywords": [ 138 | "bootstrap", 139 | "javascript", 140 | "jquery", 141 | "plugin", 142 | "treegrid", 143 | "treeview" 144 | ], 145 | "time": "2015-02-03T14:17:28+00:00" 146 | }, 147 | { 148 | "name": "bower-asset/jquery.cookie", 149 | "version": "v1.4.1", 150 | "source": { 151 | "type": "git", 152 | "url": "https://github.com/carhartl/jquery-cookie.git", 153 | "reference": "7f88a4e631aba8a8c688fd8999ce6b9bcfd50718" 154 | }, 155 | "dist": { 156 | "type": "zip", 157 | "url": "https://api.github.com/repos/carhartl/jquery-cookie/zipball/7f88a4e631aba8a8c688fd8999ce6b9bcfd50718", 158 | "reference": "7f88a4e631aba8a8c688fd8999ce6b9bcfd50718", 159 | "shasum": "" 160 | }, 161 | "require": { 162 | "bower-asset/jquery": ">=1.2" 163 | }, 164 | "type": "bower-asset-library", 165 | "extra": { 166 | "bower-asset-main": [ 167 | "./jquery.cookie.js" 168 | ], 169 | "bower-asset-ignore": [ 170 | "test", 171 | ".*", 172 | "*.json", 173 | "*.md", 174 | "*.txt", 175 | "Gruntfile.js" 176 | ] 177 | }, 178 | "time": "2014-04-27T20:07:15+00:00" 179 | }, 180 | { 181 | "name": "bower-asset/punycode", 182 | "version": "v1.3.2", 183 | "source": { 184 | "type": "git", 185 | "url": "https://github.com/bestiejs/punycode.js.git", 186 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" 187 | }, 188 | "dist": { 189 | "type": "zip", 190 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", 191 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", 192 | "shasum": "" 193 | }, 194 | "type": "bower-asset-library", 195 | "extra": { 196 | "bower-asset-main": "punycode.js", 197 | "bower-asset-ignore": [ 198 | "coverage", 199 | "tests", 200 | ".*", 201 | "component.json", 202 | "Gruntfile.js", 203 | "node_modules", 204 | "package.json" 205 | ] 206 | }, 207 | "time": "2014-10-22T12:02:42+00:00" 208 | }, 209 | { 210 | "name": "bower-asset/yii2-pjax", 211 | "version": "2.0.7.1", 212 | "source": { 213 | "type": "git", 214 | "url": "https://github.com/yiisoft/jquery-pjax.git", 215 | "reference": "aef7b953107264f00234902a3880eb50dafc48be" 216 | }, 217 | "dist": { 218 | "type": "zip", 219 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/aef7b953107264f00234902a3880eb50dafc48be", 220 | "reference": "aef7b953107264f00234902a3880eb50dafc48be", 221 | "shasum": "" 222 | }, 223 | "require": { 224 | "bower-asset/jquery": ">=1.8" 225 | }, 226 | "type": "bower-asset-library", 227 | "extra": { 228 | "bower-asset-main": "./jquery.pjax.js", 229 | "bower-asset-ignore": [ 230 | ".travis.yml", 231 | "Gemfile", 232 | "Gemfile.lock", 233 | "CONTRIBUTING.md", 234 | "vendor/", 235 | "script/", 236 | "test/" 237 | ] 238 | }, 239 | "license": [ 240 | "MIT" 241 | ], 242 | "time": "2017-10-12T10:11:14+00:00" 243 | }, 244 | { 245 | "name": "cebe/markdown", 246 | "version": "1.2.1", 247 | "source": { 248 | "type": "git", 249 | "url": "https://github.com/cebe/markdown.git", 250 | "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" 251 | }, 252 | "dist": { 253 | "type": "zip", 254 | "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", 255 | "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", 256 | "shasum": "" 257 | }, 258 | "require": { 259 | "lib-pcre": "*", 260 | "php": ">=5.4.0" 261 | }, 262 | "require-dev": { 263 | "cebe/indent": "*", 264 | "facebook/xhprof": "*@dev", 265 | "phpunit/phpunit": "4.1.*" 266 | }, 267 | "bin": [ 268 | "bin/markdown" 269 | ], 270 | "type": "library", 271 | "extra": { 272 | "branch-alias": { 273 | "dev-master": "1.2.x-dev" 274 | } 275 | }, 276 | "autoload": { 277 | "psr-4": { 278 | "cebe\\markdown\\": "" 279 | } 280 | }, 281 | "notification-url": "https://packagist.org/downloads/", 282 | "license": [ 283 | "MIT" 284 | ], 285 | "authors": [ 286 | { 287 | "name": "Carsten Brandt", 288 | "email": "mail@cebe.cc", 289 | "homepage": "http://cebe.cc/", 290 | "role": "Creator" 291 | } 292 | ], 293 | "description": "A super fast, highly extensible markdown parser for PHP", 294 | "homepage": "https://github.com/cebe/markdown#readme", 295 | "keywords": [ 296 | "extensible", 297 | "fast", 298 | "gfm", 299 | "markdown", 300 | "markdown-extra" 301 | ], 302 | "time": "2018-03-26T11:24:36+00:00" 303 | }, 304 | { 305 | "name": "ezyang/htmlpurifier", 306 | "version": "v4.13.0", 307 | "source": { 308 | "type": "git", 309 | "url": "https://github.com/ezyang/htmlpurifier.git", 310 | "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" 311 | }, 312 | "dist": { 313 | "type": "zip", 314 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", 315 | "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", 316 | "shasum": "" 317 | }, 318 | "require": { 319 | "php": ">=5.2" 320 | }, 321 | "require-dev": { 322 | "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" 323 | }, 324 | "type": "library", 325 | "autoload": { 326 | "psr-0": { 327 | "HTMLPurifier": "library/" 328 | }, 329 | "files": [ 330 | "library/HTMLPurifier.composer.php" 331 | ], 332 | "exclude-from-classmap": [ 333 | "/library/HTMLPurifier/Language/" 334 | ] 335 | }, 336 | "notification-url": "https://packagist.org/downloads/", 337 | "license": [ 338 | "LGPL-2.1-or-later" 339 | ], 340 | "authors": [ 341 | { 342 | "name": "Edward Z. Yang", 343 | "email": "admin@htmlpurifier.org", 344 | "homepage": "http://ezyang.com" 345 | } 346 | ], 347 | "description": "Standards compliant HTML filter written in PHP", 348 | "homepage": "http://htmlpurifier.org/", 349 | "keywords": [ 350 | "html" 351 | ], 352 | "time": "2020-06-29T00:56:53+00:00" 353 | }, 354 | { 355 | "name": "yiisoft/yii2", 356 | "version": "2.0.38", 357 | "source": { 358 | "type": "git", 359 | "url": "https://github.com/yiisoft/yii2-framework.git", 360 | "reference": "fd01e747cc66a049ec105048f0ab8dfbdf60bf4b" 361 | }, 362 | "dist": { 363 | "type": "zip", 364 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/fd01e747cc66a049ec105048f0ab8dfbdf60bf4b", 365 | "reference": "fd01e747cc66a049ec105048f0ab8dfbdf60bf4b", 366 | "shasum": "" 367 | }, 368 | "require": { 369 | "bower-asset/inputmask": "~3.2.2 | ~3.3.5", 370 | "bower-asset/jquery": "3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", 371 | "bower-asset/punycode": "1.3.*", 372 | "bower-asset/yii2-pjax": "~2.0.1", 373 | "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0", 374 | "ext-ctype": "*", 375 | "ext-mbstring": "*", 376 | "ezyang/htmlpurifier": "~4.6", 377 | "lib-pcre": "*", 378 | "php": ">=5.4.0", 379 | "yiisoft/yii2-composer": "~2.0.4" 380 | }, 381 | "bin": [ 382 | "yii" 383 | ], 384 | "type": "library", 385 | "extra": { 386 | "branch-alias": { 387 | "dev-master": "2.0.x-dev" 388 | } 389 | }, 390 | "autoload": { 391 | "psr-4": { 392 | "yii\\": "" 393 | } 394 | }, 395 | "notification-url": "https://packagist.org/downloads/", 396 | "license": [ 397 | "BSD-3-Clause" 398 | ], 399 | "authors": [ 400 | { 401 | "name": "Qiang Xue", 402 | "email": "qiang.xue@gmail.com", 403 | "homepage": "http://www.yiiframework.com/", 404 | "role": "Founder and project lead" 405 | }, 406 | { 407 | "name": "Alexander Makarov", 408 | "email": "sam@rmcreative.ru", 409 | "homepage": "http://rmcreative.ru/", 410 | "role": "Core framework development" 411 | }, 412 | { 413 | "name": "Maurizio Domba", 414 | "homepage": "http://mdomba.info/", 415 | "role": "Core framework development" 416 | }, 417 | { 418 | "name": "Carsten Brandt", 419 | "email": "mail@cebe.cc", 420 | "homepage": "http://cebe.cc/", 421 | "role": "Core framework development" 422 | }, 423 | { 424 | "name": "Timur Ruziev", 425 | "email": "resurtm@gmail.com", 426 | "homepage": "http://resurtm.com/", 427 | "role": "Core framework development" 428 | }, 429 | { 430 | "name": "Paul Klimov", 431 | "email": "klimov.paul@gmail.com", 432 | "role": "Core framework development" 433 | }, 434 | { 435 | "name": "Dmitry Naumenko", 436 | "email": "d.naumenko.a@gmail.com", 437 | "role": "Core framework development" 438 | }, 439 | { 440 | "name": "Boudewijn Vahrmeijer", 441 | "email": "info@dynasource.eu", 442 | "homepage": "http://dynasource.eu", 443 | "role": "Core framework development" 444 | } 445 | ], 446 | "description": "Yii PHP Framework Version 2", 447 | "homepage": "http://www.yiiframework.com/", 448 | "keywords": [ 449 | "framework", 450 | "yii2" 451 | ], 452 | "funding": [ 453 | { 454 | "url": "https://github.com/yiisoft", 455 | "type": "github" 456 | }, 457 | { 458 | "url": "https://opencollective.com/yiisoft", 459 | "type": "open_collective" 460 | }, 461 | { 462 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2", 463 | "type": "tidelift" 464 | } 465 | ], 466 | "time": "2020-09-14T21:52:10+00:00" 467 | }, 468 | { 469 | "name": "yiisoft/yii2-composer", 470 | "version": "2.0.10", 471 | "source": { 472 | "type": "git", 473 | "url": "https://github.com/yiisoft/yii2-composer.git", 474 | "reference": "94bb3f66e779e2774f8776d6e1bdeab402940510" 475 | }, 476 | "dist": { 477 | "type": "zip", 478 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/94bb3f66e779e2774f8776d6e1bdeab402940510", 479 | "reference": "94bb3f66e779e2774f8776d6e1bdeab402940510", 480 | "shasum": "" 481 | }, 482 | "require": { 483 | "composer-plugin-api": "^1.0 | ^2.0" 484 | }, 485 | "require-dev": { 486 | "composer/composer": "^1.0 | ^2.0@dev", 487 | "phpunit/phpunit": "<7" 488 | }, 489 | "type": "composer-plugin", 490 | "extra": { 491 | "class": "yii\\composer\\Plugin", 492 | "branch-alias": { 493 | "dev-master": "2.0.x-dev" 494 | } 495 | }, 496 | "autoload": { 497 | "psr-4": { 498 | "yii\\composer\\": "" 499 | } 500 | }, 501 | "notification-url": "https://packagist.org/downloads/", 502 | "license": [ 503 | "BSD-3-Clause" 504 | ], 505 | "authors": [ 506 | { 507 | "name": "Qiang Xue", 508 | "email": "qiang.xue@gmail.com" 509 | }, 510 | { 511 | "name": "Carsten Brandt", 512 | "email": "mail@cebe.cc" 513 | } 514 | ], 515 | "description": "The composer plugin for Yii extension installer", 516 | "keywords": [ 517 | "composer", 518 | "extension installer", 519 | "yii2" 520 | ], 521 | "funding": [ 522 | { 523 | "url": "https://github.com/yiisoft", 524 | "type": "github" 525 | }, 526 | { 527 | "url": "https://opencollective.com/yiisoft", 528 | "type": "open_collective" 529 | }, 530 | { 531 | "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-composer", 532 | "type": "tidelift" 533 | } 534 | ], 535 | "time": "2020-06-24T00:04:01+00:00" 536 | } 537 | ], 538 | "packages-dev": [ 539 | { 540 | "name": "phpunit/php-code-coverage", 541 | "version": "1.2.18", 542 | "source": { 543 | "type": "git", 544 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 545 | "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" 546 | }, 547 | "dist": { 548 | "type": "zip", 549 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", 550 | "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", 551 | "shasum": "" 552 | }, 553 | "require": { 554 | "php": ">=5.3.3", 555 | "phpunit/php-file-iterator": ">=1.3.0@stable", 556 | "phpunit/php-text-template": ">=1.2.0@stable", 557 | "phpunit/php-token-stream": ">=1.1.3,<1.3.0" 558 | }, 559 | "require-dev": { 560 | "phpunit/phpunit": "3.7.*@dev" 561 | }, 562 | "suggest": { 563 | "ext-dom": "*", 564 | "ext-xdebug": ">=2.0.5" 565 | }, 566 | "type": "library", 567 | "extra": { 568 | "branch-alias": { 569 | "dev-master": "1.2.x-dev" 570 | } 571 | }, 572 | "autoload": { 573 | "classmap": [ 574 | "PHP/" 575 | ] 576 | }, 577 | "notification-url": "https://packagist.org/downloads/", 578 | "include-path": [ 579 | "" 580 | ], 581 | "license": [ 582 | "BSD-3-Clause" 583 | ], 584 | "authors": [ 585 | { 586 | "name": "Sebastian Bergmann", 587 | "email": "sb@sebastian-bergmann.de", 588 | "role": "lead" 589 | } 590 | ], 591 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 592 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 593 | "keywords": [ 594 | "coverage", 595 | "testing", 596 | "xunit" 597 | ], 598 | "time": "2014-09-02T10:13:14+00:00" 599 | }, 600 | { 601 | "name": "phpunit/php-file-iterator", 602 | "version": "1.4.5", 603 | "source": { 604 | "type": "git", 605 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 606 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" 607 | }, 608 | "dist": { 609 | "type": "zip", 610 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", 611 | "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", 612 | "shasum": "" 613 | }, 614 | "require": { 615 | "php": ">=5.3.3" 616 | }, 617 | "type": "library", 618 | "extra": { 619 | "branch-alias": { 620 | "dev-master": "1.4.x-dev" 621 | } 622 | }, 623 | "autoload": { 624 | "classmap": [ 625 | "src/" 626 | ] 627 | }, 628 | "notification-url": "https://packagist.org/downloads/", 629 | "license": [ 630 | "BSD-3-Clause" 631 | ], 632 | "authors": [ 633 | { 634 | "name": "Sebastian Bergmann", 635 | "email": "sb@sebastian-bergmann.de", 636 | "role": "lead" 637 | } 638 | ], 639 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 640 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 641 | "keywords": [ 642 | "filesystem", 643 | "iterator" 644 | ], 645 | "time": "2017-11-27T13:52:08+00:00" 646 | }, 647 | { 648 | "name": "phpunit/php-text-template", 649 | "version": "1.2.1", 650 | "source": { 651 | "type": "git", 652 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 653 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 654 | }, 655 | "dist": { 656 | "type": "zip", 657 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 658 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 659 | "shasum": "" 660 | }, 661 | "require": { 662 | "php": ">=5.3.3" 663 | }, 664 | "type": "library", 665 | "autoload": { 666 | "classmap": [ 667 | "src/" 668 | ] 669 | }, 670 | "notification-url": "https://packagist.org/downloads/", 671 | "license": [ 672 | "BSD-3-Clause" 673 | ], 674 | "authors": [ 675 | { 676 | "name": "Sebastian Bergmann", 677 | "email": "sebastian@phpunit.de", 678 | "role": "lead" 679 | } 680 | ], 681 | "description": "Simple template engine.", 682 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 683 | "keywords": [ 684 | "template" 685 | ], 686 | "time": "2015-06-21T13:50:34+00:00" 687 | }, 688 | { 689 | "name": "phpunit/php-timer", 690 | "version": "1.0.9", 691 | "source": { 692 | "type": "git", 693 | "url": "https://github.com/sebastianbergmann/php-timer.git", 694 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" 695 | }, 696 | "dist": { 697 | "type": "zip", 698 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 699 | "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", 700 | "shasum": "" 701 | }, 702 | "require": { 703 | "php": "^5.3.3 || ^7.0" 704 | }, 705 | "require-dev": { 706 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" 707 | }, 708 | "type": "library", 709 | "extra": { 710 | "branch-alias": { 711 | "dev-master": "1.0-dev" 712 | } 713 | }, 714 | "autoload": { 715 | "classmap": [ 716 | "src/" 717 | ] 718 | }, 719 | "notification-url": "https://packagist.org/downloads/", 720 | "license": [ 721 | "BSD-3-Clause" 722 | ], 723 | "authors": [ 724 | { 725 | "name": "Sebastian Bergmann", 726 | "email": "sb@sebastian-bergmann.de", 727 | "role": "lead" 728 | } 729 | ], 730 | "description": "Utility class for timing", 731 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 732 | "keywords": [ 733 | "timer" 734 | ], 735 | "time": "2017-02-26T11:10:40+00:00" 736 | }, 737 | { 738 | "name": "phpunit/php-token-stream", 739 | "version": "1.2.2", 740 | "source": { 741 | "type": "git", 742 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 743 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" 744 | }, 745 | "dist": { 746 | "type": "zip", 747 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", 748 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", 749 | "shasum": "" 750 | }, 751 | "require": { 752 | "ext-tokenizer": "*", 753 | "php": ">=5.3.3" 754 | }, 755 | "type": "library", 756 | "extra": { 757 | "branch-alias": { 758 | "dev-master": "1.2-dev" 759 | } 760 | }, 761 | "autoload": { 762 | "classmap": [ 763 | "PHP/" 764 | ] 765 | }, 766 | "notification-url": "https://packagist.org/downloads/", 767 | "include-path": [ 768 | "" 769 | ], 770 | "license": [ 771 | "BSD-3-Clause" 772 | ], 773 | "authors": [ 774 | { 775 | "name": "Sebastian Bergmann", 776 | "email": "sb@sebastian-bergmann.de", 777 | "role": "lead" 778 | } 779 | ], 780 | "description": "Wrapper around PHP's tokenizer extension.", 781 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 782 | "keywords": [ 783 | "tokenizer" 784 | ], 785 | "abandoned": true, 786 | "time": "2014-03-03T05:10:30+00:00" 787 | }, 788 | { 789 | "name": "phpunit/phpunit", 790 | "version": "3.7.38", 791 | "source": { 792 | "type": "git", 793 | "url": "https://github.com/sebastianbergmann/phpunit.git", 794 | "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" 795 | }, 796 | "dist": { 797 | "type": "zip", 798 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", 799 | "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", 800 | "shasum": "" 801 | }, 802 | "require": { 803 | "ext-ctype": "*", 804 | "ext-dom": "*", 805 | "ext-json": "*", 806 | "ext-pcre": "*", 807 | "ext-reflection": "*", 808 | "ext-spl": "*", 809 | "php": ">=5.3.3", 810 | "phpunit/php-code-coverage": "~1.2", 811 | "phpunit/php-file-iterator": "~1.3", 812 | "phpunit/php-text-template": "~1.1", 813 | "phpunit/php-timer": "~1.0", 814 | "phpunit/phpunit-mock-objects": "~1.2", 815 | "symfony/yaml": "~2.0" 816 | }, 817 | "require-dev": { 818 | "pear-pear.php.net/pear": "1.9.4" 819 | }, 820 | "suggest": { 821 | "phpunit/php-invoker": "~1.1" 822 | }, 823 | "bin": [ 824 | "composer/bin/phpunit" 825 | ], 826 | "type": "library", 827 | "extra": { 828 | "branch-alias": { 829 | "dev-master": "3.7.x-dev" 830 | } 831 | }, 832 | "autoload": { 833 | "classmap": [ 834 | "PHPUnit/" 835 | ] 836 | }, 837 | "notification-url": "https://packagist.org/downloads/", 838 | "include-path": [ 839 | "", 840 | "../../symfony/yaml/" 841 | ], 842 | "license": [ 843 | "BSD-3-Clause" 844 | ], 845 | "authors": [ 846 | { 847 | "name": "Sebastian Bergmann", 848 | "email": "sebastian@phpunit.de", 849 | "role": "lead" 850 | } 851 | ], 852 | "description": "The PHP Unit Testing framework.", 853 | "homepage": "http://www.phpunit.de/", 854 | "keywords": [ 855 | "phpunit", 856 | "testing", 857 | "xunit" 858 | ], 859 | "time": "2014-10-17T09:04:17+00:00" 860 | }, 861 | { 862 | "name": "phpunit/phpunit-mock-objects", 863 | "version": "1.2.3", 864 | "source": { 865 | "type": "git", 866 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 867 | "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" 868 | }, 869 | "dist": { 870 | "type": "zip", 871 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", 872 | "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", 873 | "shasum": "" 874 | }, 875 | "require": { 876 | "php": ">=5.3.3", 877 | "phpunit/php-text-template": ">=1.1.1@stable" 878 | }, 879 | "suggest": { 880 | "ext-soap": "*" 881 | }, 882 | "type": "library", 883 | "autoload": { 884 | "classmap": [ 885 | "PHPUnit/" 886 | ] 887 | }, 888 | "notification-url": "https://packagist.org/downloads/", 889 | "include-path": [ 890 | "" 891 | ], 892 | "license": [ 893 | "BSD-3-Clause" 894 | ], 895 | "authors": [ 896 | { 897 | "name": "Sebastian Bergmann", 898 | "email": "sb@sebastian-bergmann.de", 899 | "role": "lead" 900 | } 901 | ], 902 | "description": "Mock Object library for PHPUnit", 903 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 904 | "keywords": [ 905 | "mock", 906 | "xunit" 907 | ], 908 | "abandoned": true, 909 | "time": "2013-01-13T10:24:48+00:00" 910 | }, 911 | { 912 | "name": "symfony/yaml", 913 | "version": "v2.8.33", 914 | "source": { 915 | "type": "git", 916 | "url": "https://github.com/symfony/yaml.git", 917 | "reference": "be720fcfae4614df204190d57795351059946a77" 918 | }, 919 | "dist": { 920 | "type": "zip", 921 | "url": "https://api.github.com/repos/symfony/yaml/zipball/be720fcfae4614df204190d57795351059946a77", 922 | "reference": "be720fcfae4614df204190d57795351059946a77", 923 | "shasum": "" 924 | }, 925 | "require": { 926 | "php": ">=5.3.9" 927 | }, 928 | "type": "library", 929 | "extra": { 930 | "branch-alias": { 931 | "dev-master": "2.8-dev" 932 | } 933 | }, 934 | "autoload": { 935 | "psr-4": { 936 | "Symfony\\Component\\Yaml\\": "" 937 | }, 938 | "exclude-from-classmap": [ 939 | "/Tests/" 940 | ] 941 | }, 942 | "notification-url": "https://packagist.org/downloads/", 943 | "license": [ 944 | "MIT" 945 | ], 946 | "authors": [ 947 | { 948 | "name": "Fabien Potencier", 949 | "email": "fabien@symfony.com" 950 | }, 951 | { 952 | "name": "Symfony Community", 953 | "homepage": "https://symfony.com/contributors" 954 | } 955 | ], 956 | "description": "Symfony Yaml Component", 957 | "homepage": "https://symfony.com", 958 | "time": "2018-01-03T07:36:31+00:00" 959 | } 960 | ], 961 | "aliases": [], 962 | "minimum-stability": "stable", 963 | "stability-flags": [], 964 | "prefer-stable": false, 965 | "prefer-lowest": false, 966 | "platform": [], 967 | "platform-dev": [], 968 | "plugin-api-version": "1.1.0" 969 | } 970 | --------------------------------------------------------------------------------