diff --git a/docs/post-types/Creating-columns.md b/docs/post-types/Creating-columns.md index 6561bba..ba9f030 100644 --- a/docs/post-types/Creating-columns.md +++ b/docs/post-types/Creating-columns.md @@ -34,35 +34,38 @@ class PriceColumn extends Column } /** - * Populate column callback. + * Position a column before/after another. * - * @return void + * @return array */ - public function populate( int $post_id ): void + public function position(): array { - echo '$' . get_post_meta( $post_id, '_price', true ); + return $this->after( 'title' ); } /** - * Set the column can be sorted. + * Populate column callback. * - * @return boolean + * @return callable */ - public function isSortable(): bool + public function populate(): callable { - return true; + return function( int $post_id ) { + echo '$' . get_post_meta( $post_id, '_price', true ); + }; } /** * Handle sorting the column by modifying the admin query. * - * @param $query \WP_Query - * @return void + * @return callable */ - public function sort(\WP_Query $query): void + public function sort(): callable { - $query->set( 'meta_key', '_price' ); - $query->set( 'orderby', 'meta_value_num' ); + return function( \WP_Query $query ) { + $query->set( 'meta_key', '_price' ); + $query->set( 'orderby', 'meta_value_num' ); + }; } } ``` diff --git a/docs/post-types/Modifying-columns.md b/docs/post-types/Modifying-columns.md index 362e300..0f10f3d 100644 --- a/docs/post-types/Modifying-columns.md +++ b/docs/post-types/Modifying-columns.md @@ -4,7 +4,7 @@ To modify a post types admin columns use the `column()` method. This method acce ## Adding Columns -To add columns to the admin edit screen pass an array of column slugs and labels to the `add()` method. +To add a column to the admin edit screen pass a column ket and label to the `label()` method. ```php use PostTypes\PostType; @@ -22,7 +22,7 @@ class Books extends PostType public function columns( Columns $column ): Columns { // Add a new price column. - $columns->add( 'price', __( 'Price', 'my-text-domain' ) ); + $columns->label( 'price', __( 'Price', 'my-text-domain' ) ); // Populate the price column with post meta. $columns->populate( 'price', function( $post_id ) { @@ -125,9 +125,9 @@ class Books extends PostType } ``` -## Column Order +## Column Positions -To rearrange columns pass an array of column slugs and position to the `order()` method. Only olumns you want to reorder need to be set, not all columns. +To rearrange columns pass an array of column slugs and position to the `position()` method. Only olumns you want to reorder need to be set, not all columns. ```php @@ -145,11 +145,8 @@ class Books extends PostType */ public function columns( Columns $column ): Columns { - // Order the new Rating and Genre columns. - $columns->order( [ - 'rating' => 2, - 'genre' => 4, - ] ); + // Position the rating column after the title column. + $columns->position( 'rating', 'after', 'title' ); return $columns; } diff --git a/docs/taxonomies/Modifying-columns.md b/docs/taxonomies/Modifying-columns.md index 0a5d1a3..be6d72f 100644 --- a/docs/taxonomies/Modifying-columns.md +++ b/docs/taxonomies/Modifying-columns.md @@ -22,7 +22,7 @@ class Genres extends Taxonomy public function columns( Columns $column ): Columns { // Add a new Popularity column. - $columns->add( 'popularity', __( 'Popularity', 'my-text-domain' ) ); + $columns->label( 'popularity', __( 'Popularity', 'my-text-domain' ) ); // Populate the popularity column with term meta. $columns->populate( 'popularity', function( $term_id ) { @@ -147,10 +147,8 @@ class Genres extends Taxonomy */ public function columns( Columns $column ): Columns { - // Order the new Popularity column. - $columns->order( [ - 'popularity' => 2, - ] ); + // Position the new Popularity column. + $columns->position( 'popularity', 'after', 'title' ); return $columns; } diff --git a/examples/Genres.php b/examples/Genres.php index 5086a7a..1d46939 100644 --- a/examples/Genres.php +++ b/examples/Genres.php @@ -20,21 +20,15 @@ public function posttypes(): array { } public function columns( Columns $columns ): Columns { - $columns->remove(['posts']); + $columns->remove( [ 'posts' ] ); - $columns->add( - 'popularity', - __( 'Popularity', 'post-types' ), - function( $term_id ) { - echo get_term_meta( $term_id, 'popularity', true ); - } - ); + $columns->label( 'popularity', __( 'Popularity', 'post-types' ) ); - $columns->order( [ - 'popularity' => 2, - ] ); + $columns->populate( 'popularity', function( $term_id ) { + echo get_term_meta( $term_id, 'popularity', true ); + } ); - $columns->sortable( 'popularity', function( $query ) { + $columns->sort( 'popularity', function( $query ) { $query->query_vars['orderby'] = 'meta_value'; $query->query_vars['meta_key'] = 'popularity'; } ); diff --git a/examples/Price.php b/examples/Price.php index 6246a79..f161c1e 100644 --- a/examples/Price.php +++ b/examples/Price.php @@ -12,20 +12,20 @@ public function label(): string { return __( 'Price', 'post-types' ); } - public function order(): int { - return 2; + public function position(): array { + return $this->after( 'title' ); } - public function populate( int $post_id ): void { - echo '£' . get_post_meta( $post_id, 'price', true ); + public function populate(): callable { + return function( int $post_id ) { + echo '£' . get_post_meta( $post_id, 'price', true ); + }; } - public function isSortable(): bool { - return true; - } - - public function sort( $query ): void { - $query->set('orderby', 'meta_value_num'); - $query->set('meta_key', 'price'); + public function sort(): callable { + return function( $query ) { + $query->set( 'orderby', 'meta_value_num' ); + $query->set( 'meta_key', 'price' ); + }; } } diff --git a/examples/books.php b/examples/books.php index a3c5e32..13d2b9a 100644 --- a/examples/books.php +++ b/examples/books.php @@ -70,23 +70,29 @@ public function columns( Columns $columns ): Columns { $columns->column( new Price ); - $columns->add( 'rating', __( 'Rating', 'post-types' ) ); + $columns->label( 'rating', __( 'Rating', 'post-types' ) ); + + $columns->position( 'rating', 'after', 'price' ); $columns->populate( 'rating', function( $post_id ) { echo get_post_meta( $post_id, 'rating', true ); } ); - $columns->sortable( 'rating', function( $query ) { + $columns->sort( 'rating', function( $query ) { $query->set('orderby', 'meta_value_num'); $query->set('meta_key', 'rating'); } ); - $columns->order( [ - 'price' => 4, - 'rating' => 5, - 'taxonomy-genre' => 2, - 'tags' => 3, - ] ); + $columns->add( 'rating' ) + ->after( 'price' ) + ->label( __( 'Rating', 'post-types' ) ) + ->populate( function( $post_id ) { + echo get_post_meta( $post_id, 'rating', true ); + } ) + ->sort( function( $query ) { + $query->set('orderby', 'meta_value_num'); + $query->set('meta_key', 'rating'); + } ); return $columns; } diff --git a/src/Column.php b/src/Column.php index 857c7b0..8e3ec39 100644 --- a/src/Column.php +++ b/src/Column.php @@ -26,42 +26,52 @@ public function label(): string /** * Populate the column. * - * @param integer $objectId - * @return void + * @return callable|null */ - public function populate(int $objectId): void + public function populate(): ?callable { - return; + return null; } /** * Set the column order. * - * @return integer|null + * @return array|null + */ + public function position(): ?array + { + return null; + } + + /** + * Return the sort callback for the column. + * + * @return callable|null */ - public function order(): ?int + public function sort(): ?callable { return null; } /** - * Handle sorting the column. + * Return the before position array structure. * - * @param \WP_Query|\WP_Term_Query $query - * @return void + * @param string $reference + * @return array */ - public function sort($query) + protected function before(string $reference): array { - return; + return ['before', $reference]; } /** - * Can the column be sorted. + * Return the after position array structure. * - * @return boolean + * @param string $reference + * @return array */ - public function isSortable(): bool + protected function after(string $reference): array { - return false; + return ['after', $reference]; } } diff --git a/src/ColumnBuilder.php b/src/ColumnBuilder.php new file mode 100644 index 0000000..5dc823d --- /dev/null +++ b/src/ColumnBuilder.php @@ -0,0 +1,107 @@ +columns = $columns; + $this->key = $key; + } + + /** + * Set the label for the column. + * + * @param string $label + * @return ColumnBuilder + */ + public function label(string $label): ColumnBuilder + { + $this->columns->label($this->key, $label); + + return $this; + } + + /** + * Position a column. + * + * @param string $direction + * @param string $reference + * @return ColumnBuilder + */ + public function position(string $direction, string $reference): ColumnBuilder + { + $this->columns->position($this->key, $direction, $reference); + + return $this; + } + + /** + * Position a column after another. + * + * @param string $reference + * @return ColumnBuilder + */ + public function after(string $reference): ColumnBuilder + { + return $this->position('after', $reference); + } + + /** + * Position a column before another. + * + * @param string $reference + * @return ColumnBuilder + */ + public function before(string $reference): ColumnBuilder + { + return $this->position('before', $reference); + } + + /** + * Set columns populate callback. + * + * @param callable $callback + * @return ColumnBuilder + */ + public function populate(callable $callback): ColumnBuilder + { + $this->columns->populate($this->key, $callback); + + return $this; + } + + /** + * Set columns sort callback. + * + * @param callable $callback + * @return ColumnBuilder + */ + public function sort(callable $callback): ColumnBuilder + { + $this->columns->sort($this->key, $callback); + + return $this; + } +} diff --git a/src/Columns.php b/src/Columns.php index a217dc2..709622d 100644 --- a/src/Columns.php +++ b/src/Columns.php @@ -2,44 +2,74 @@ namespace PostTypes; +use InvalidArgumentException; use PostTypes\Contracts\ColumnContract; class Columns { /** - * Columns to add. + * Columns keys and labels. * * @var array */ - public $add = []; + protected $labels = []; /** - * Column populate callbacks. + * Columns to remove. * * @var array */ - public $populate = []; + protected $remove = []; /** - * Columns to remove. + * Columns whitelist. * * @var array */ - public $remove = []; + protected $only = []; /** - * Columns order. + * Column positions. * * @var array */ - public $order = []; + protected $positions = []; + + /** + * Column populate callbacks. + * + * @var array + */ + protected $populateCallbacks = []; /** * Sortable columns and sort callbacks. * * @var array */ - public $sortable = []; + protected $sortCallbacks = []; + + /** + * Create a new Column. + * + * @param string $key + * @return ColumnBuilder + */ + public function add(string $key): ColumnBuilder + { + return new ColumnBuilder($this, $key); + } + + /** + * Modify an existing column. + * + * @param string $key + * @return ColumnBuilder + */ + public function modify(string $key): ColumnBuilder + { + return $this->add($key); + } /** * Add a column object. @@ -47,70 +77,87 @@ class Columns * @param ColumnContract $column * @return void */ - public function column(ColumnContract $column) + public function column(ColumnContract $column): void { - $this->add($column->name(), $column->label()); + $this->label($column->name(), $column->label()); + + if (!is_null($column->position())) { + [$direction, $reference] = $column->position(); - $this->populate($column->name(), [$column, 'populate']); + $this->position($column->name(), $direction, $reference); + } - if (!is_null($column->order())) { - $this->order[$column->name()] = $column->order(); + if ($callback = $column->populate()) { + $this->populate($column->name(), $callback); } - if ($column->isSortable()) { - $this->sortable($column->name(), [$column, 'sort']); + if ($callback = $column->sort()) { + $this->sort($column->name(), $callback); } } /** - * Add a column. + * Remove columns. * - * @param string $key - * @param string $label - * @param callable|null $callback + * @param array $keys * @return void */ - public function add(string $key, string $label, ?callable $callback = null) + public function remove(array $keys): void { - $this->add[$key] = $label; + $this->remove = array_merge($this->remove, $keys); + } - if (is_callable($callback)) { - $this->populate($key, $callback); - } + /** + * Set columns. + * + * @param array $keys + * @return void + */ + public function only(array $keys): void + { + $this->only = array_merge($this->only, $keys); } /** - * Set column populate callback. + * Set the label for a column. * * @param string $key - * @param callable $callback + * @param string $label * @return void */ - public function populate(string $key, callable $callback) + public function label(string $key, string $label): void { - $this->populate[$key] = $callback; + $this->labels[$key] = $label; } /** - * Remove columns. + * Set column position. * - * @param array $keys + * @param string $key + * @param string $direction + * @param string $reference * @return void + * @throws InvalidArgumentException */ - public function remove(array $keys) + public function position(string $key, string $direction, string $reference): void { - $this->remove = array_merge($this->remove, $keys); + if (!in_array($direction, ['before', 'after'], true)) { + throw new InvalidArgumentException("Invalid position direction '{$direction}'"); + } + + $this->positions[$key] = [$direction, $reference]; } /** - * Set columns order + * Set column populate callback. * - * @param array $order + * @param string $key + * @param callable $callback * @return void */ - public function order(array $order) + public function populate(string $key, callable $callback): void { - $this->order = array_merge($this->order, $order); + $this->populateCallbacks[$key] = $callback; } /** @@ -120,92 +167,80 @@ public function order(array $order) * @param callable $callback * @return void */ - public function sortable(string $key, callable $callback) + public function sort(string $key, callable $callback): void { - $this->sortable[$key] = $callback; + $this->sortCallbacks[$key] = $callback; } /** - * Apply columns. + * Get columns to add. * - * @param array $columns * @return array */ - public function applyColumns(array $columns) + public function getColumns(): array { - if (!empty($this->add)) { - $columns = array_merge($columns, $this->add); - } - - if (!empty($this->remove)) { - $columns = array_diff_key($columns, array_flip($this->remove)); - } - - if (!empty($this->order)) { - $order = $this->order; - - // Sort the order array. - asort($order); - - // Flip order so the index is the position. - $order = array_flip($order); - - // Create the current order array. - $current = array_keys($columns); - - // Loop over the order. - foreach ($order as $index => $key) { - array_splice($current, $index, 0, $key); - } + return $this->labels; + } - $new = array_flip(array_unique($current)); + /** + * Get removed columns. + * + * @return array + */ + public function getRemoved(): array + { + return $this->remove; + } - $columns = array_merge($new, $columns); - } + /** + * Get only columns. + * + * @return array + */ + public function getOnly(): array + { + return $this->only; + } - return $columns; + /** + * Get column positions. + * + * @return array + */ + public function getPositions(): array + { + return $this->positions; } /** - * Populate a column. + * Get a column populate callback. * - * @param string $column - * @param array $params - * @return void + * @param string $key + * @return callable|null */ - public function populateColumn(string $column, array $params) + public function getPopulateCallback(string $key): ?callable { - if (isset($this->populate[$column]) && is_callable($this->populate[$column])) { - call_user_func_array($this->populate[$column], $params); - } + return $this->populateCallbacks[$key] ?? null; } /** - * Set sortable columns + * Get sortable columns. * - * @param array $columns * @return array */ - public function setSortable(array $columns): array + public function getSortableColumns(): array { - foreach (array_keys($this->sortable) as $key) { - $columns[$key] = $key; - } - - return $columns; + return array_combine(array_keys($this->sortCallbacks), array_keys($this->sortCallbacks)); } /** - * Sort a column. + * Get column sort callback. * - * @param string $column - * @param \WP_Query|\WP_Term_Query $query - * @return void + * @param string $key + * @return callable|null */ - public function sortColumn(string $column, $query) + public function getSortCallback(string $key): ?callable { - if (isset($this->sortable[$column]) && is_callable($this->sortable[$column])) { - call_user_func_array($this->sortable[$column], [$query]); - } + return $this->sortCallbacks[$key] ?? null; } } diff --git a/src/Contracts/ColumnContract.php b/src/Contracts/ColumnContract.php index 45c955e..12fa9c1 100644 --- a/src/Contracts/ColumnContract.php +++ b/src/Contracts/ColumnContract.php @@ -19,32 +19,23 @@ public function name(): string; public function label(): string; /** - * Populate the column. + * Set the column position. * - * @param integer $objectId - * @return void + * @return array|null */ - public function populate(int $objectId): void; + public function position(): ?array; /** - * Set the column order. + * Populate the column. * - * @return integer|null + * @return callable|null */ - public function order(): ?int; + public function populate(): ?callable; /** * Handle sorting the column. * - * @param \WP_Query|\WP_Term_Query $query - * @return void - */ - public function sort($query); - - /** - * Can the column be sorted. - * - * @return boolean + * @return callable|null */ - public function isSortable(): bool; + public function sort(): ?callable; } diff --git a/src/Registrars/PostTypeRegistrar.php b/src/Registrars/PostTypeRegistrar.php index 361e63e..2a5703b 100644 --- a/src/Registrars/PostTypeRegistrar.php +++ b/src/Registrars/PostTypeRegistrar.php @@ -171,7 +171,43 @@ public function modifyFilters($posttype) */ public function modifyColumns(array $columns) { - return $this->columns->applyColumns($columns); + foreach ($this->columns->getColumns() as $key => $label) { + $columns[$key] = $label; + } + + if ($remove = $this->columns->getRemoved()) { + $columns = array_diff_key($columns, array_flip($remove)); + } + + if ($only = $this->columns->getOnly()) { + $columns = array_intersect_key($columns, array_flip($only)); + } + + foreach ($this->columns->getPositions() as $key => $position) { + [$direction, $reference] = $position; + + if (!isset($direction) || !isset($reference)) { + continue; + } + + $new = []; + + foreach ($columns as $k => $label) { + if ('before' === $direction && $k === $reference) { + $new[$key] = $columns[$key]; + } + + $new[$k] = $label; + + if ('after' === $direction && $k === $reference) { + $new[$key] = $columns[$key]; + } + } + + $columns = $new; + } + + return $columns; } /** @@ -183,7 +219,11 @@ public function modifyColumns(array $columns) */ public function populateColumns($column, $post_id) { - $this->columns->populateColumn($column, [$post_id]); + $callback = $this->columns->getPopulateCallback($column); + + if ($callback) { + call_user_func_array($callback, [$post_id]); + } } /** @@ -194,7 +234,9 @@ public function populateColumns($column, $post_id) */ public function setSortableColumns($columns) { - return $this->columns->setSortable($columns); + $sortable = $this->columns->getSortableColumns(); + + return array_merge($columns, $sortable); } /** @@ -210,7 +252,10 @@ public function sortSortableColumns($query) } $column = $query->get('orderby'); + $callback = $this->columns->getSortCallback($column); - $this->columns->sortColumn($column, $query); + if ($callback) { + call_user_func_array($callback, [$query]); + } } } diff --git a/src/Registrars/TaxonomyRegistrar.php b/src/Registrars/TaxonomyRegistrar.php index 23363ba..ca1bd46 100644 --- a/src/Registrars/TaxonomyRegistrar.php +++ b/src/Registrars/TaxonomyRegistrar.php @@ -115,7 +115,43 @@ public function registerTaxonomyToPostTypes() */ public function modifyColumns(array $columns) { - return $this->columns->applyColumns($columns); + foreach ($this->columns->getColumns() as $key => $label) { + $columns[$key] = $label; + } + + if ($remove = $this->columns->getRemoved()) { + $columns = array_diff_key($columns, array_flip($remove)); + } + + if ($only = $this->columns->getOnly()) { + $columns = array_intersect_key($columns, array_flip($only)); + } + + foreach ($this->columns->getPositions() as $key => $position) { + [$direction, $reference] = $position; + + if (!isset($direction) || !isset($reference)) { + continue; + } + + $new = []; + + foreach ($columns as $k => $label) { + if ('before' === $direction && $k === $reference) { + $new[$key] = $columns[$key]; + } + + $new[$k] = $label; + + if ('after' === $direction && $k === $reference) { + $new[$key] = $columns[$key]; + } + } + + $columns = $new; + } + + return $columns; } /** @@ -128,7 +164,11 @@ public function modifyColumns(array $columns) */ public function populateColumns($content, $column, $term_id) { - $this->columns->populateColumn($column, [$term_id, $content]); + $callback = $this->columns->getPopulateCallback($column); + + if ($callback) { + call_user_func_array($callback, [$term_id, $content]); + } } /** @@ -139,7 +179,7 @@ public function populateColumns($content, $column, $term_id) */ public function setSortableColumns($columns) { - return $this->columns->setSortable($columns); + return array_merge($columns, $this->columns->getSortableColumns()); } /** @@ -155,7 +195,10 @@ public function sortSortableColumns($query) } $column = $query->query_vars['orderby']; + $callback = $this->columns->getSortCallback($column); - $this->columns->sortColumn($column, $query); + if ($callback) { + call_user_func_array($callback, [$query]); + } } } diff --git a/tests/ColumBuilderTest.php b/tests/ColumBuilderTest.php new file mode 100644 index 0000000..daed557 --- /dev/null +++ b/tests/ColumBuilderTest.php @@ -0,0 +1,122 @@ +createMock(Columns::class); + + $columns->expects($this->once()) + ->method('label') + ->with('price', 'Price Label'); + + $builder = new ColumnBuilder($columns, 'price'); + + $result = $builder->label('Price Label'); + + $this->assertSame($builder, $result); + } + + public function test_position_sets_position_correctly() + { + $columns = $this->createMock(Columns::class); + + $columns->expects($this->once()) + ->method('position') + ->with('price', 'after', 'title'); + + $builder = new ColumnBuilder($columns, 'price'); + + $result = $builder->position('after', 'title'); + + $this->assertSame($builder, $result); + } + + public function test_after_sets_position_after_reference() + { + $columns = $this->createMock(Columns::class); + + $columns->expects($this->once()) + ->method('position') + ->with('price', 'after', 'title'); + + $builder = new ColumnBuilder($columns, 'price'); + + $result = $builder->after('title'); + + $this->assertSame($builder, $result); + } + + public function test_before_sets_position_before_reference() + { + $columns = $this->createMock(Columns::class); + + $columns->expects($this->once()) + ->method('position') + ->with('price', 'before', 'title'); + + $builder = new ColumnBuilder($columns, 'price'); + + $result = $builder->before('title'); + + $this->assertSame($builder, $result); + } + + public function test_populate_sets_populate_callback() + { + $callback = function () {}; + + $columns = $this->createMock(Columns::class); + + $columns->expects($this->once()) + ->method('populate') + ->with('price', $callback); + + $builder = new ColumnBuilder($columns, 'price'); + + $result = $builder->populate($callback); + + $this->assertSame($builder, $result); + } + + public function test_sort_sets_sort_callback() + { + $callback = function () {}; + + $columns = $this->createMock(Columns::class); + + $columns->expects($this->once()) + ->method('sort') + ->with('price', $callback); + + $builder = new ColumnBuilder($columns, 'price'); + + $result = $builder->sort($callback); + + $this->assertSame($builder, $result); + } + + public function test_builder_fluency_all_methods_chain() + { + $columns = $this->createMock(Columns::class); + + $columns->expects($this->once())->method('label')->with('price', 'Price'); + $columns->expects($this->once())->method('position')->with('price', 'after', 'title'); + $columns->expects($this->once())->method('populate'); + $columns->expects($this->once())->method('sort'); + + $builder = new ColumnBuilder($columns, 'price'); + + $result = $builder + ->label('Price') + ->after('title') + ->populate(function () {}) + ->sort(function () {}); + + $this->assertSame($builder, $result); + } +} diff --git a/tests/ColumnTest.php b/tests/ColumnTest.php index 4bafa1a..bc86be8 100644 --- a/tests/ColumnTest.php +++ b/tests/ColumnTest.php @@ -15,9 +15,8 @@ public function test_column_returns_defaults() $this->assertEquals('price', $stub->name()); $this->assertEquals('Price', $stub->label()); - $this->assertEquals(null, $stub->populate(1)); - $this->assertEquals(null, $stub->order()); - $this->assertEquals(null, $stub->sort(true)); - $this->assertEquals(false, $stub->isSortable()); + $this->assertEquals(null, $stub->populate()); + $this->assertEquals(null, $stub->position()); + $this->assertEquals(null, $stub->sort()); } } diff --git a/tests/ColumnsTest.php b/tests/ColumnsTest.php index 7500015..aa6ede4 100644 --- a/tests/ColumnsTest.php +++ b/tests/ColumnsTest.php @@ -1,57 +1,85 @@ add('column', 'Test Column'); + $columns->label('column', 'Test Column'); - $this->assertArrayHasKey('column', $columns->add); - $this->assertSame('Test Column', $columns->add['column']); + $output = $columns->getColumns(); + + $this->assertArrayHasKey('column', $output); + $this->assertSame('Test Column', $output['column']); } public function test_can_add_column_with_column_class() { - $stub = $this->getMockForAbstractClass(Column::class); + $stub = $this->createMock(ColumnContract::class); - $stub->expects($this->any()) - ->method('name') - ->will($this->returnValue('column')); + $stub->method('name')->willReturn('column'); + $stub->method('label')->willReturn('Column'); + $stub->method('position')->willReturn(['after', 'title']); + $stub->method('populate')->willReturn(function () {}); + $stub->method('sort')->willReturn(function () {}); $columns = new Columns; $columns->column($stub); - $this->assertArrayHasKey('column', $columns->add); - $this->assertSame('Column', $columns->add['column']); + $output = $columns->getColumns(); + $positions = $columns->getPositions(); + $populate = $columns->getPopulateCallback('column'); + $sortable = $columns->getSortCallback('column'); + + $this->assertArrayHasKey('column', $output); + $this->assertSame('Column', $output['column']); + + $this->assertArrayHasKey('column', $positions); + $this->assertSame(['after', 'title'], $positions['column']); + + $this->assertIsCallable($populate); + $this->assertIsCallable($sortable); + } + + public function test_add_returns_column_builder() + { + $columns = new Columns; - $this->assertArrayHasKey('column', $columns->populate); - $this->assertIsCallable($columns->populate['column']); + $builder = $columns->add('new_column'); + + $this->assertInstanceOf(ColumnBuilder::class, $builder); } - public function test_can_add_column_with_populate_callback() + public function test_modify_returns_column_builder() { $columns = new Columns; - $columns->add('column', 'Test Column', function() {}); + $builder = $columns->modify('existing'); - $this->assertArrayHasKey('column', $columns->populate); - $this->assertIsCallable($columns->populate['column']); + $this->assertInstanceOf(ColumnBuilder::class, $builder); } public function test_can_set_column_populate_callback() { $columns = new Columns; - $columns->populate('column', function() {}); + $callback = function () {}; + $columns->populate('column', $callback); + + $this->assertSame($callback, $columns->getPopulateCallback('column')); + } - $this->assertArrayHasKey('column', $columns->populate); - $this->assertIsCallable($columns->populate['column']); + public function test_get_populate_callback_returns_null_for_missing_key() + { + $columns = new Columns; + + $this->assertNull($columns->getPopulateCallback('missing')); } public function test_can_set_remove_column() @@ -60,7 +88,7 @@ public function test_can_set_remove_column() $columns->remove(['column']); - $this->assertEquals(['column'], $columns->remove); + $this->assertEquals(['column'], $columns->getRemoved()); } public function test_can_set_remove_columns_with_multiple_calls() @@ -70,150 +98,100 @@ public function test_can_set_remove_columns_with_multiple_calls() $columns->remove(['column']); $columns->remove(['column_2']); - $this->assertEquals(['column', 'column_2'], $columns->remove); + $this->assertEquals(['column', 'column_2'], $columns->getRemoved()); } - public function test_can_set_order_columns() + public function test_can_set_only_columns() { $columns = new Columns; - $columns->order([ - 'column' => 1, - ]); + $columns->only(['one']); + $columns->only(['two']); - $this->assertEquals(['column' => 1], $columns->order); + $this->assertEquals(['one', 'two'], $columns->getOnly()); } - public function test_can_set_order_columns_with_multiple_calls() + public function test_can_set_position_after() { $columns = new Columns; - $columns->order(['column' => 1]); - $columns->order(['column_2' => 3]); + $columns->position('col', 'after', 'title'); - $this->assertEquals(['column' => 1, 'column_2' => 3], $columns->order); + $this->assertSame(['after', 'title'], $columns->getPositions()['col']); } - public function test_can_order_column_with_column_class() + public function test_can_set_position_before() { $columns = new Columns; - $stub = $this->createMock(Column::class); - - $stub->expects($this->any()) - ->method('name') - ->will($this->returnValue('column')); - - $stub->expects($this->any()) - ->method('order') - ->will($this->returnValue(1)); + $columns->position('col', 'before', 'date'); + $this->assertSame(['before', 'date'], $columns->getPositions()['col']); + } - $columns->column($stub); + public function test_position_throws_exception_for_invalid_direction() + { + $this->expectException(InvalidArgumentException::class); - $this->assertEquals(['column' => 1], $columns->order); + $columns = new Columns; + $columns->position('col', 'sideways', 'title'); } public function test_can_set_sortable_column() { $columns = new Columns; - $columns->sortable('column', function() {}); + $callback = function () {}; + $columns->sort('column', $callback); - $this->assertArrayHasKey('column', $columns->sortable); - $this->assertIsCallable($columns->sortable['column']); + $this->assertSame($callback, $columns->getSortCallback('column')); } - public function test_can_apply_columns() + public function test_get_sortable_columns_returns_keys_mapped_to_keys() { $columns = new Columns; - $columns->add('column_5', 'Column 5'); + $columns->sort('a', function () {}); + $columns->sort('b', function () {}); - $columns->remove(['column_2']); - - $columns->order([ - 'column_3' => 0, - ]); - - $original = [ - 'column_1' => 'Column 1', - 'column_2' => 'Column 2', - 'column_3' => 'Column 3', - 'column_4' => 'Column 4', - ]; - - $modified = $columns->applyColumns($original); - - $expected = [ - 'column_3' => 'Column 3', - 'column_1' => 'Column 1', - 'column_4' => 'Column 4', - 'column_5' => 'Column 5', - ]; - - $this->assertSame($expected, $modified); + $this->assertSame(['a' => 'a', 'b' => 'b'], $columns->getSortableColumns()); } - public function test_can_populate_column() + public function test_get_sortable_callback_returns_null_for_missing_key() { $columns = new Columns; - $stub = $this->createMock(Column::class); - - $stub->expects($this->any()) - ->method('name') - ->will($this->returnValue('column')); - - $stub->expects($this->once()) - ->method('populate') - ->with($this->greaterThan(0)); - - $columns->column($stub); - - $columns->populateColumn('column', [1]); + $this->assertNull($columns->getSortCallback('missing')); } - public function test_can_add_sortable_columns_to_sortable_list() + public function test_populate_does_not_affect_sort_callbacks() { $columns = new Columns; - $columns->sortable('column', function() {}); - - $sortable = [ - 'title' => 'title', - ]; - - $sortable = $columns->setSortable($sortable); + $columns->populate('col', function () {}); - $expected = [ - 'title' => 'title', - 'column' => 'column', - ]; - - $this->assertSame($expected, $sortable); + $this->assertNull($columns->getSortCallback('col')); } - public function test_can_sort_column() + public function test_sort_does_not_affect_populate_callbacks() { $columns = new Columns; - $stub = $this->createMock(Column::class); - - $stub->expects($this->any()) - ->method('name') - ->will($this->returnValue('column')); + $columns->sort('col', function () {}); - $stub->expects($this->once()) - ->method('isSortable') - ->will($this->returnValue(true)); + $this->assertNull($columns->getPopulateCallback('col')); + } - $stub->expects($this->once()) - ->method('sort') - ->with($this->greaterThan(0)); + public function test_add_does_not_overwrite_callback_data() + { + $columns = new Columns; - $columns->column($stub); + $columns->populate('col', function () {}); + $columns->sort('col', function () {}); + $columns->add('col', 'Label'); - $columns->sortColumn('column', 1); + // Callbacks remain unchanged + $this->assertIsCallable($columns->getPopulateCallback('col')); + $this->assertIsCallable($columns->getSortCallback('col')); } } diff --git a/tests/Registrars/PostTypeRegistrarTest.php b/tests/Registrars/PostTypeRegistrarTest.php index eb480e2..0ac3db1 100644 --- a/tests/Registrars/PostTypeRegistrarTest.php +++ b/tests/Registrars/PostTypeRegistrarTest.php @@ -80,7 +80,7 @@ public function test_can_modify_columns() ]; $columns = new Columns; - $columns->add('date', 'Date', function() {}); + $columns->label('date', 'Date'); $stub = $this->getMockBuilder(PostType::class) ->getMock(); @@ -119,7 +119,7 @@ public function test_can_populate_column() $stub->expects($this->once()) ->method('populate') - ->will($this->returnValue(true)); + ->willReturnCallback(function() {}); $columns->column($stub); @@ -142,7 +142,7 @@ public function test_can_populate_column() public function test_can_set_sortable_columns() { $columns = new Columns; - $columns->sortable('column', function() {}); + $columns->sort('column', function() {}); $sortable = [ 'title' => 'title', diff --git a/tests/Registrars/TaxonomyRegistrarTest.php b/tests/Registrars/TaxonomyRegistrarTest.php index 15e62a9..697b0f7 100644 --- a/tests/Registrars/TaxonomyRegistrarTest.php +++ b/tests/Registrars/TaxonomyRegistrarTest.php @@ -68,7 +68,7 @@ public function test_can_modify_columns() ]; $columns = new Columns; - $columns->add('popularity', 'Popularity', function() {}); + $columns->label('popularity', 'Popularity'); $stub = $this->getMockBuilder(Taxonomy::class) ->getMock(); @@ -106,7 +106,7 @@ public function test_can_populate_column() $stub->expects($this->once()) ->method('populate') - ->will($this->returnValue(true)); + ->willReturnCallback(function() {}); $columns->column($stub); @@ -129,7 +129,7 @@ public function test_can_populate_column() public function test_can_set_sortable_columns() { $columns = new Columns; - $columns->sortable('column', function() {}); + $columns->sort('column', function() {}); $sortable = [ 'title' => 'title',