Skip to content

Commit 625a3c8

Browse files
committed
rework architecture so that users can create any number of body class rules.
1 parent 5924010 commit 625a3c8

File tree

5 files changed

+306
-19
lines changed

5 files changed

+306
-19
lines changed

src/Generators/FullRoutePath.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Zschuessler\RouteToClass\Generators;
4+
5+
/**
6+
* Class FullRoutePath
7+
*
8+
* A route2class generator which converts a full route path to a single class, sans parameters.
9+
*
10+
* Example:
11+
*
12+
* ```
13+
* Route: /admin/product/12/edit
14+
*
15+
* Generates: admin-product-edit
16+
* ```
17+
*
18+
* Note that the product ID parameter is removed.
19+
*
20+
* @author Zachary Schuessler <zlschuessler@gmail.com>
21+
* @package Zschuessler\RouteToClass\Generators
22+
* @see https://github.com/zschuessler/laravel-route-to-class
23+
*/
24+
class FullRoutePath extends GeneratorAbstract
25+
{
26+
public function generateClassName()
27+
{
28+
// Remove route parameters. product_id is removed here: `controller/product/{product_id}`
29+
$className = preg_replace("/\{([^}]+)\}/", '', $this->getRoute()->getPath());
30+
31+
// Remove characters that aren't alpha, numeric, or dashes
32+
$className = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $className);
33+
34+
// Remove any double dashes from replace functions. eg: `product--name` should be `product-name`
35+
$className = strtolower(trim($className, '-'));
36+
37+
// Replace special characters with a dash
38+
$className = preg_replace("/[\/_|+ -]+/", '-', $className);
39+
40+
return $className;
41+
}
42+
}

src/Generators/GeneratorAbstract.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Zschuessler\RouteToClass\Generators;
4+
5+
/**
6+
* Class GeneratorAbstract
7+
*
8+
* An abstract class for creating custom route2class generators.
9+
*
10+
* Simply extend this class and create the `generateClassName` method, which has the sole job
11+
* of returning a string.
12+
*
13+
* @author Zachary Schuessler <zlschuessler@gmail.com>
14+
* @package Zschuessler\RouteToClass\Generators
15+
* @see https://github.com/zschuessler/laravel-route-to-class
16+
*/
17+
abstract class GeneratorAbstract
18+
{
19+
20+
/**
21+
* Priority
22+
*
23+
* Assign priority to the generator. Defaults to 100, lower
24+
* numbers are treated as higher priority when loading.
25+
*
26+
* @var int
27+
*/
28+
public $priority = 100;
29+
30+
/**
31+
* Route
32+
*
33+
* The Illuminate route instance.
34+
*
35+
* @var \Illuminate\Routing\Route
36+
*/
37+
public $route;
38+
39+
/**
40+
* Generate Class Name
41+
*
42+
* Extend this function to provide logic for generating a class string.
43+
*
44+
* @return string
45+
*/
46+
abstract public function generateClassName();
47+
48+
/**
49+
* @param $route
50+
*
51+
* @return $this
52+
*/
53+
public function setRoute($route)
54+
{
55+
$this->route = $route;
56+
57+
return $this;
58+
}
59+
60+
/**
61+
* @return \Illuminate\Routing\Route
62+
*/
63+
public function getRoute()
64+
{
65+
return $this->route;
66+
}
67+
}

src/RouteToClass.php

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<?php
2+
3+
namespace Zschuessler\RouteToClass;
4+
5+
class RouteToClass
6+
{
7+
/**
8+
* Classes
9+
*
10+
* The authoritative array of body classes to render.
11+
*
12+
* @var \Illuminate\Support\Collection
13+
*/
14+
private $classes;
15+
16+
/**
17+
* Route
18+
*
19+
* The Illuminate route. Used to build body class names.
20+
*
21+
* @var \Illuminate\Routing\Route
22+
*/
23+
private $route;
24+
25+
/**
26+
* Generators
27+
*
28+
* A collection of class names to load as rules, for generating
29+
* body classes.
30+
*
31+
* @var \Illuminate\Support\Collection
32+
*/
33+
private $generators;
34+
35+
public function __construct()
36+
{
37+
$this->classes = collect([]);
38+
$this->route = request()->route();
39+
$this->generators = collect(config('routetoclass.generators'));
40+
}
41+
42+
/**
43+
* Get Classes
44+
*
45+
* Gets internal classes property.
46+
*
47+
* @return \Illuminate\Support\CollectionG
48+
*/
49+
public function getClasses()
50+
{
51+
return $this->classes;
52+
}
53+
54+
/**
55+
* Add Class
56+
*
57+
* Allows setting a class ad-hoc, without a generator.
58+
*
59+
* Example:
60+
*
61+
* ```
62+
* app()['route2class']->addClass('my-class-name');
63+
* ```
64+
*
65+
* @param $value string The class name.
66+
* @param bool $sanitizeClassString Whether to clean the class name input. (eg remove special chars)
67+
*
68+
* @return $this
69+
*/
70+
public function addClass($value, $sanitizeClassString = true)
71+
{
72+
$class = '';
73+
74+
// Value is a string
75+
if (true === is_string($value)) {
76+
$class = $value;
77+
}
78+
79+
// Value is a callable function
80+
if (true === is_callable($value)) {
81+
$callableResult = $value();
82+
83+
if (!is_string($callableResult)) {
84+
throw new Exception(
85+
'User called function did not return a string for method addClass.'
86+
);
87+
}
88+
89+
$class = $callableResult;
90+
}
91+
92+
// Sanitize string unless override parameter set
93+
if (true === $sanitizeClassString) {
94+
$class = $this->sanitizeClassString($value);
95+
}
96+
97+
// Add class to stack
98+
$this->classes->push($class);
99+
100+
return $this;
101+
}
102+
103+
/**
104+
* Sanitize CSS Class String
105+
*
106+
* Currently a simple wrapper around the `str_slug` method in Laravel.
107+
*
108+
* @param $value string The class name to sanitize.
109+
*
110+
* @return string A sanitized class name (a valid css class, eg no special characters).
111+
*/
112+
public function sanitizeClassString($value)
113+
{
114+
return str_slug($value);
115+
}
116+
117+
/**
118+
* Generate Class String
119+
*
120+
* Generates the full body class string.
121+
*
122+
* @return mixed
123+
*/
124+
public function generateClassString()
125+
{
126+
// Load all generators, sorted by priority
127+
$generators = $this->generators
128+
->map(function($generatorClassName) {
129+
$generator = new $generatorClassName;
130+
$generator->setRoute($this->route);
131+
132+
return $generator;
133+
})
134+
->sortBy('priority');
135+
136+
// Run all generators
137+
$classes = $generators->map(function($generatorClass) {
138+
return [get_class() => $generatorClass->generateClassName()];
139+
});
140+
141+
// Allow any prior-set classes to take precedence over generators.
142+
$classes->merge($this->classes);
143+
144+
$classString = $classes
145+
->map(function($className) {
146+
return array_values($className)[0];
147+
})
148+
->implode(' ');
149+
150+
return $classString;
151+
}
152+
}

src/ServiceProvider.php

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,40 @@
33
namespace Zschuessler\RouteToClass;
44

55
use Illuminate\Support\Facades\View;
6+
use Zschuessler\RouteToClass\RouteToClass;
67

78
class ServiceProvider extends \Illuminate\Support\ServiceProvider
89
{
910
/**
11+
* Register the service provider.
12+
*/
13+
public function register()
14+
{
15+
// Merge config
16+
$this->mergeConfigFrom(
17+
__DIR__.'/config/routetoclass.php', 'routetoclass'
18+
);
19+
20+
// Create app singleton
21+
$this->app->singleton('route2class', function () {
22+
return new RouteToClass();
23+
});
24+
}
25+
/**
26+
* Bootstrap the application services.
27+
*
28+
* Creates a view composer for all views.
29+
* Assigns the variable `route_body_classes` to each view.
30+
*
1031
* @return void
1132
*/
1233
public function boot()
1334
{
14-
/**
35+
/*
1536
* Register View composer
1637
*
17-
* Share global view variable `$route_body_classes`, which is a unique body class
18-
* inflected based on the route path.
19-
*
20-
* example: `/admin/products/25/edit` becomes `admin-products-edit`
38+
* Share global view variable `$route_body_classes`, which represents the final body class
39+
* string after all generators have run.
2140
*/
2241
View::composer('*', function (\Illuminate\View\View $view) {
2342

@@ -26,21 +45,9 @@ public function boot()
2645
return;
2746
}
2847

29-
$route = request()->route()->getPath();
30-
31-
// Remove route parameters. product_id is removed here: `controller/product/{product_id}`
32-
$clean = preg_replace("/\{([^}]+)\}/", '', $route);
33-
34-
// Remove characters that aren't alpha, numeric, or dashes
35-
$clean = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
36-
37-
// Remove any double dashes from replace functions. eg: `product--name` should be `product-name`
38-
$clean = strtolower(trim($clean, '-'));
39-
40-
// Replace special characters with a dash
41-
$clean = preg_replace("/[\/_|+ -]+/", '-', $clean);
48+
$routeToClass = app()['route2class'];
4249

43-
View::share('route_body_classes', $clean);
50+
View::share('route_body_classes', $routeToClass->generateClassString());
4451
});
4552
}
4653
}

src/config/routetoclass.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
return [
3+
/**
4+
* Generators
5+
*
6+
* An array of classes to use in generating body classes.
7+
*/
8+
'generators' => [
9+
/**
10+
* Full Route Path
11+
*
12+
* The full route is converted to a class string.
13+
*
14+
* eg:
15+
* `/admin/product/12/edit` becomes `admin-product-edit`
16+
*/
17+
\Zschuessler\RouteToClass\Generators\FullRoutePath::class
18+
]
19+
];

0 commit comments

Comments
 (0)