Repository: dwightwatson/active Branch: master Commit: 181107fc90b9 Files: 16 Total size: 32.9 KB Directory structure: gitextract_29gsk6bh/ ├── .github/ │ └── workflows/ │ └── run-tests.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── composer.json ├── phpunit.xml ├── src/ │ ├── Active.php │ ├── ActiveServiceProvider.php │ ├── Facades/ │ │ └── Active.php │ ├── Route.php │ ├── config/ │ │ └── config.php │ └── helpers.php └── tests/ ├── .gitkeep ├── ActiveTest.php ├── RouteTest.php └── helpersTest.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/run-tests.yml ================================================ name: run-tests on: ['push'] jobs: test: runs-on: ${{ matrix.os }} strategy: fail-fast: true matrix: os: [ubuntu-latest, windows-latest] php: [8.2, 8.3, 8.4, 8.5] laravel: [10.*, 11.*, 12.*, 13.*] stability: [prefer-lowest, prefer-stable] exclude: - php: 8.2 laravel: 13.* include: - laravel: 10.* testbench: 8.* - laravel: 11.* testbench: 9.* - laravel: 12.* testbench: 10.* - laravel: 13.* testbench: 11.* name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo coverage: none - name: Install dependencies run: | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests run: vendor/bin/phpunit ================================================ FILE: .gitignore ================================================ /vendor composer.phar composer.lock .DS_Store .idea/ ================================================ FILE: LICENSE.txt ================================================ The MIT License (MIT) Copyright (c) 2014 Dwight Watson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ Active for Laravel ================== [![Build Status](https://travis-ci.org/dwightwatson/active.png?branch=master)](https://travis-ci.org/dwightwatson/active) [![Total Downloads](https://poser.pugx.org/watson/active/downloads.svg)](https://packagist.org/packages/watson/active) [![Latest Stable Version](https://poser.pugx.org/watson/active/v/stable.svg)](https://packagist.org/packages/watson/active) [![Latest Unstable Version](https://poser.pugx.org/watson/active/v/unstable.svg)](https://packagist.org/packages/watson/active) [![License](https://poser.pugx.org/watson/active/license.svg)](https://packagist.org/packages/watson/active) [![Buy us a tree](https://img.shields.io/badge/Treeware-%F0%9F%8C%B3-lightgreen)](https://plant.treeware.earth/dwightwatson/active) Active is a helper package for Laravel that makes it easy to recognize the current path or route, useful for adding 'active' classes (like those used in the Boostrap framework) and performing other actions only when a certain route is active. It also includes helpers for retrieving the current controller and action names. ## Installation First, simply require the package through Composer. ```sh composer require watson/active ``` **Using Laravel 5.1? The latest version of the package that will work for you is 2.0.4.** Next, add the service provider in your `config/app.php` file. `Watson\Active\ActiveServiceProvider::class` If you'd like to use the Facade instead of the helper functions, add it to the `aliases` array. `'Active' => Watson\Active\Facades\Active::class` ## Using Active ### Helper functions Active ships with a couple of helper functions which make it easy to use without the facade or creating an instance of your own. ```php active() is_active() ``` ### Using `active()` You pass an array of routes or paths you want to see are the current page, and if any match this function will return the string `active`, for Bootstrap. Alternatively, you can pass a custom return string as the second argument. ```php active(['login', 'users/*', 'posts.*', 'pages.contact']); // Returns 'active' if the current route matches any path or route name. active(['login', 'logout'], 'active-class'); // Returns 'active-class' if the current route is 'login' or 'logout'. active(['login', 'logout'], 'active-class', 'fallback-class'); // Returns 'fallback-class' if the current route is not 'login' or 'logout'. ``` In the first example, the function will return the string `active` if the current path is `login`, starts with `users/` or if the name of the current route is `posts.create`. Do note that a number of argument types are provided: you can use a path string, you can use a path string with a wildcard (using the `*`) and you can also use named routes. You can use this function with your links to give them an active state. ```php All posts ``` You can also provide certain paths or routes to be exluded when being considered. ```php active(['pages/*', 'not:pages/contact']) active(['pages.*', 'not:pages.contact']) ``` ### Using `is_active()` This works much the same as `active()`, you can pass the paths and routes to it but instead it will return a boolean if the current page matches. ```php @if (is_active('posts/*')) You're looking at a blog post! @endif ``` ### Additional helpers Two additional functions are provided to get the current controller and action, if your routing is being handled by a controller for a request. These functions will return the lowercase controller/action name, without the method of the request. Here is an example for a request that is routed to `FooController@getBar': ```php $controller = controller_name(); // foo $action = action_name(); // bar ``` ## Licence Active for Laravel is 100% free and open-source, under the [MIT license](LICENSE.txt). Use it however you want. This package is [Treeware](https://treeware.earth). If you use it in production, then we ask that you [**buy the world a tree**](https://plant.treeware.earth/dwightwatson/active) to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats. ================================================ FILE: composer.json ================================================ { "name": "watson/active", "description": "Laravel helper for recognising the current route, controller and action", "keywords": [ "laravel", "active", "routing" ], "license": "MIT", "authors": [ { "name": "Dwight Watson", "email": "dwight@studiousapp.com" } ], "require": { "php": "^8.2", "illuminate/config": "^10.0|^11.0||^12.0||^13.0", "illuminate/http": "^10.0|^11.0||^12.0||^13.0", "illuminate/routing": "^10.0|^11.0||^12.0||^13.0", "illuminate/support": "^10.0|^11.0||^12.0||^13.0" }, "require-dev": { "phpunit/phpunit": "^9.0|^10.5|^11.0", "mockery/mockery": "^1.5.1" }, "autoload": { "psr-4": { "Watson\\Active\\": "src/" }, "files": [ "src/helpers.php" ] }, "extra": { "laravel": { "providers": [ "Watson\\Active\\ActiveServiceProvider" ], "aliases": { "Active": "Watson\\Watson\\Facades\\Active" } } }, "minimum-stability": "dev", "prefer-stable": true } ================================================ FILE: phpunit.xml ================================================ src/ src/Facades src/ActiveServiceProvider.php ./tests/ ================================================ FILE: src/Active.php ================================================ request = $request; $this->router = $router; $this->config = $config; } /** * Determine if any of the provided routes are active. * * @param mixed $routes * @return bool */ public function isActive($routes) { $routes = is_array($routes) ? $routes : func_get_args(); list($routes, $ignoredRoutes) = $this->parseIgnoredRoutes($routes); if ($this->isPath($routes) || $this->isFullPath($routes) || $this->isRoute($routes)) { if (count($ignoredRoutes) && ($this->isPath($ignoredRoutes) || $this->isFullPath($routes) || $this->isRoute($ignoredRoutes))) { return false; } return true; } return false; } /** * Get the active class if the active path is provided. * * @param mixed $routes * @param string $class * @param null $fallbackClass * @return string|null */ public function active($routes, $class = null, $fallbackClass = null) { $routes = (array) $routes; if ($this->isActive($routes)) { return $this->getActiveClass($class); } if ($fallbackClass) { return $fallbackClass; } } /** * Determine if the current path is one of the provided paths. * * @param mixed $routes * @return boolean */ public function isPath($routes) { $routes = is_array($routes) ? $routes : func_get_args(); return call_user_func_array([$this->request, 'is'], $routes); } /** * Determine if the current full path is one of the provided paths. * * @param mixed $routes * @return boolean */ public function isFullPath($routes) { $routes = is_array($routes) ? $routes : func_get_args(); return call_user_func_array([$this->request, 'fullUrlIs'], $routes); } /** * Get the active class if the active path is provided. * * @param mixed $routes * @param string $class * @return string|null */ public function path($routes, $class = null) { $routes = (array) $routes; if ($this->isPath($routes)) { return $this->getActiveClass($class); } } /** * Determin if the current route is one of the provided routes. * * @param mixed $routes * @return boolean */ public function isRoute($routes) { $routes = is_array($routes) ? $routes : func_get_args(); return call_user_func_array([$this->router, 'is'], $routes); } /** * Get the active class if the active route is provided. * * @param mixed $routes * @param string $class * @return string|null */ public function route($routes, $class = null) { $routes = (array) $routes; if ($this->isRoute($routes)) { return $this->getActiveClass($class); } } /** * Return the active class if it is provided, otherwise fall back * to the class set in the configuration. * * @param string $class * @return string */ protected function getActiveClass($class = null) { return $class ?: $this->config->get('active.class'); } /** * Separate ignored routes from the provided routes. * * @param mixed $routes * @return array */ private function parseIgnoredRoutes($routes) { $ignoredRoutes = []; $routes = is_array($routes) ? $routes : func_get_args(); foreach ($routes as $index => $route) { if (Str::startsWith($route, 'not:')) { $ignoredRoute = substr($route, 4); unset($routes[$index]); $ignoredRoutes[] = $ignoredRoute; } } return [$routes, $ignoredRoutes]; } } ================================================ FILE: src/ActiveServiceProvider.php ================================================ app->bind('active', Active::class); $this->mergeConfigFrom( __DIR__ . '/config/config.php', 'active' ); } /** * Bootstrap the application events. * * @return void */ public function boot() { $this->publishes([ __DIR__ . '/config/config.php' => config_path('active.php'), ], 'config'); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return ['active']; } } ================================================ FILE: src/Facades/Active.php ================================================ router = $router; } /** * Get the controller name, separated as necessary and with or without namespaces. * * @param string $separator * @param bool $includeNamespace * @param string $trimNamespace * @return string|null */ public function controller($separator = null, $includeNamespace = true, $trimNamespace = 'App\Http\Controllers\\') { if ($action = $this->router->currentRouteAction()) { $separator = is_null($separator) ? ' ' : $separator; $controller = head(Str::parseCallback($action, null)); // If the controller contains the given namespace, remove it. if (substr($controller, 0, strlen($trimNamespace)) === $trimNamespace) { $controller = substr($controller, strlen($trimNamespace)); } // If the controller contains 'Controller' at the end, remove it. if (substr($controller, - strlen('Controller')) === 'Controller') { $controller = substr($controller, 0, - strlen('Controller')); } // Separate out nested controller resources. $controller = str_replace('_', $separator, Str::snake($controller)); // Either separate out the namespaces or remove them. $controller = $includeNamespace ? str_replace('\\', '', $controller) : substr(strrchr($controller, '\\'), 1); return trim($controller); } return null; } /** * Get the current controller action name. * * @param bool $removeHttpMethod * @return string|null */ public function action($removeHttpMethod = true) { if ($action = $this->router->currentRouteAction()) { $action = last(Str::parseCallback($action, null)); if ($removeHttpMethod) { $action = str_replace(['get', 'post', 'patch', 'put', 'delete'], '', $action); } return Str::snake($action, '-'); } return null; } } ================================================ FILE: src/config/config.php ================================================ 'active', ]; ================================================ FILE: src/helpers.php ================================================ controller($separator, $includeNamespace, $trimNamespace); } } if ( ! function_exists('action_name')) { /** * Get the current controller action name. * * @param bool $removeHttpMethod * @return string|null */ function action_name($removeHttpMethod = true) { return App::make(Route::class)->action($removeHttpMethod); } } if ( ! function_exists('active')) { /** * Get the active class if an active path is provided. * * @param mixed $routes * @param string $class * @param null $fallbackClass * @return string|null */ function active($routes = null, $class = null, $fallbackClass = null) { if (is_null($routes)) { return App::make('active'); } $routes = is_array($routes) ? $routes : [$routes]; return active()->active($routes, $class, $fallbackClass); } } if ( ! function_exists('is_active')) { /** * Determine if any of the provided routes are active. * * @param mixed $routes * @return bool */ function is_active($routes) { $routes = is_array($routes) ? $routes : func_get_args(); return active()->isActive($routes); } } ================================================ FILE: tests/.gitkeep ================================================ ================================================ FILE: tests/ActiveTest.php ================================================ request = Mockery::mock(Request::class); $this->router = Mockery::mock(Router::class); $this->config = Mockery::mock(Repository::class); $this->active = new Active($this->request, $this->router, $this->config); } protected function tearDown(): void { parent::tearDown(); Mockery::close(); } /** @test */ public function is_active_returns_true_when_on_path() { $this->request->shouldReceive('is')->with('foo')->andReturn(true); $result = $this->active->isActive('foo'); $this->assertTrue($result, "False returned when current path provided."); } /** @test */ public function is_active_returns_true_when_on_full_path() { $this->request->shouldReceive('is')->with('/foo')->andReturn(true); $this->request->shouldReceive('fullUrlIs')->with('/foo')->andReturn(true); $result = $this->active->isActive('/foo'); $this->assertTrue($result, "False returned when current path provided."); } /** @test */ public function is_active_returns_true_when_on_route() { $this->request->shouldReceive('is')->with('home')->andReturn(false); $this->request->shouldReceive('fullUrlIs')->with('home')->andReturn(false); $this->router->shouldReceive('is')->with('home')->andReturn(true); $result = $this->active->isActive('home'); $this->assertTrue($result, "False returned when current route provided."); } /** @test */ public function is_active_returns_false_when_on_ignored_path() { $this->request->shouldReceive('is')->with('foo/*')->andReturn(true); $this->request->shouldReceive('is')->with('foo/bar')->andReturn(true); $result = $this->active->isActive('foo/*', 'not:foo/bar'); $this->assertFalse($result, "Returned true when on an ignored path."); } /** @test */ public function is_active_returns_false_when_on_ignored_route() { $this->request->shouldReceive('is')->with('pages.*')->andReturn(false); $this->request->shouldReceive('is')->with('pages.show')->andReturn(false); $this->request->shouldReceive('fullUrlIs')->with('pages.*')->andReturn(false); $this->request->shouldReceive('fullUrlIs')->with('pages.show')->andReturn(false); $this->router->shouldReceive('is')->with('pages.*')->andReturn(true); $this->router->shouldReceive('is')->with('pages.show')->andReturn(true); $result = $this->active->isActive('pages.*', 'not:pages.show'); $this->assertFalse($result, "Returned true when on an ignored route."); } /** @test */ public function is_active_returns_false_when_not_on_path_or_route() { $this->request->shouldReceive('is')->with('foo')->andReturn(false); $this->request->shouldReceive('fullUrlIs')->with('foo')->andReturn(false); $this->router->shouldReceive('is')->with('foo')->andReturn(false); $result = $this->active->isActive('foo'); $this->assertFalse($result, "Returned true when the current route or path is not provided."); } /** @test */ public function active_returns_active_when_on_path() { $this->request->shouldReceive('is')->with('foo')->andReturn(true); $this->request->shouldReceive('is')->with()->andReturn(false); $this->config->shouldReceive('get')->with('active.class')->once()->andReturn('active'); $result = $this->active->active('foo'); $this->assertEquals('active', $result, "Wrong string returned when current path provided."); } /** @test */ public function active_returns_provided_class_when_on_path() { $this->request->shouldReceive('is')->with('foo')->andReturn(true); $this->request->shouldReceive('is')->with()->andReturn(false); $result = $this->active->active('foo', 'active'); $this->assertEquals('active', $result, "Wrong string returned when current path provided."); } /** @test */ public function active_returns_provided_string_when_on_path() { $this->request->shouldReceive('is')->with('foo')->andReturn(true); $this->request->shouldReceive('is')->with()->andReturn(false); $result = $this->active->active('foo', 'bar'); $this->assertEquals('bar', $result, "Wrong string returned when current path provided."); } /** @test */ public function active_returns_null_when_not_on_path() { $this->request->shouldReceive('is')->with('foo')->andReturn(false); $this->request->shouldReceive('fullUrlIs')->with('foo')->andReturn(false); $this->router->shouldReceive('is')->with('foo')->andReturn(false); $result = $this->active->active('foo'); $this->assertNull($result, "Returned string when the current route or path is not provided."); } /** @test */ public function active_returns_fallback_when_not_on_path() { $this->request->shouldReceive('is')->with('foo')->andReturn(false); $this->request->shouldReceive('fullUrlIs')->with('foo')->andReturn(false); $this->router->shouldReceive('is')->with('foo')->andReturn(false); $result = $this->active->active('foo', 'active', 'inactive'); $this->assertEquals('inactive', $result); } /** @test */ public function path_returns_active_when_on_path() { $this->request->shouldReceive('is')->andReturn(true); $this->config->shouldReceive('get')->with('active.class')->once()->andReturn('active'); $result = $this->active->path('foo'); $this->assertEquals('active', $result, "Class is not returned when path is matched."); } /** @test */ public function path_returns_provided_string_when_on_path() { $this->request->shouldReceive('is')->andReturn(true); $result = $this->active->path('foo', 'bar'); $this->assertEquals('bar', $result, "Incorrect class is returned when path is matched."); } /** @test */ public function path_returns_null_when_not_current_path() { $this->request->shouldReceive('is')->andReturn(false); $result = $this->active->path('foo'); $this->assertNull($result, "Null is not returend when path is not matched."); } /** @test */ public function route_returns_active_when_on_route() { $this->router->shouldReceive('is')->andReturn(true); $this->config->shouldReceive('get')->with('active.class')->once()->andReturn('active'); $result = $this->active->route('foo'); $this->assertEquals('active', $result, "Class is not returned when route is matched."); } /** @test */ public function route_returns_provided_string_when_on_route() { $this->router->shouldReceive('is')->andReturn(true); $result = $this->active->route('foo', 'bar'); $this->assertEquals('bar', $result, "Class is not returned when route is matched."); } /** @test */ public function route_returns_null_when_not_current_route() { $this->router->shouldReceive('is')->andReturn(false); $result = $this->active->route('foo'); $this->assertNull($result, "Null is not returned when route is not matched."); } } ================================================ FILE: tests/RouteTest.php ================================================ router = Mockery::mock(Router::class); $this->route = new Route($this->router); } protected function tearDown(): void { parent::tearDown(); Mockery::close(); } /** @test */ public function controller_gets_controller_name() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('App\Http\Controllers\FooController@bar'); $result = $this->route->controller(); $this->assertEquals('foo', $result, "Does not get correct controller name."); } /** @test */ public function controller_gets_namespaced_controller_name() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('App\Http\Controllers\Baz\FooController@bar'); $result = $this->route->controller(); $this->assertEquals('baz foo', $result, "Does not get the correct namespaced controller name."); } /** @test */ public function controller_gets_namespaced_controller_with_separator() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('App\Http\Controllers\Baz\FooController@bar'); $result = $this->route->controller('-'); $this->assertEquals('baz-foo', $result, "Does not get the correct separated namespaced controller name."); } /** @test */ public function controller_gets_controller_without_namespace() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('App\Http\Controllers\Baz\FooController@bar'); $result = $this->route->controller(null, false); $this->assertEquals('foo', $result, "Does not get controller name without namespace."); } /** @test */ public function controller_gets_controller_with_alternate_namespace() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('Platform\Controllers\Baz\FooController@bar'); $result = $this->route->controller(null, true, 'Platform\Controllers'); $this->assertEquals('baz foo', $result, "Does not trim alternate namespace from controller."); } /** @test */ public function controller_returns_null_when_not_on_controller() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn(null); $result = $this->route->controller(); $this->assertNull($result, "Does not return null when not on controller route."); } /** @test */ public function action_gets_action_name() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('FooController@bar'); $result = $this->route->action(); $this->assertEquals('bar', $result, "Does not get correct action name."); } /** @test */ public function action_gets_kebab_case() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('FooController@barBaz'); $result = $this->route->action(); $this->assertEquals('bar-baz', $result, "Does not get correct action name."); } /** @test */ public function action_removes_http_method() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('FooController@getBar'); $result = $this->route->action(true); $this->assertEquals('bar', $result, "Does not remove the method from the action."); } /** @test */ public function action_does_not_remove_http_method() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn('FooController@getBar'); $result = $this->route->action(false); $this->assertEquals('get-bar', $result, "Removes the method from the action."); } /** @test */ public function action_returns_null_when_not_on_controller() { $this->router->shouldReceive('currentRouteAction')->once()->andReturn(null); $result = $this->route->action(); $this->assertNull($result, "Does not return null when not on controller route."); } } ================================================ FILE: tests/helpersTest.php ================================================ shouldReceive('controller')->once()->with('foo', 'bar', 'baz')->andReturn('bat'); App::shouldReceive('make')->once()->with(Route::class)->andReturn($routeMock); $result = controller_name('foo', 'bar', 'baz'); $this->assertEquals('bat', $result); } /** @test */ public function action_name_calls_action_method() { $routeMock = Mockery::mock(Route::class); $routeMock->shouldReceive('action')->once()->with('foo')->andReturn('bar'); App::shouldReceive('make')->once()->with(Route::class)->andReturn($routeMock); $result = action_name('foo'); $this->assertEquals('bar', $result); } /** @test */ public function action_without_parameters_returns_instance() { $activeMock = Mockery::mock(Active::class); App::shouldReceive('make')->once()->with('active')->andReturn($activeMock); $result = active(); $this->assertEquals($activeMock, $result); } /** @test */ public function active_calls_active_method() { $activeMock = Mockery::mock(Active::class); $activeMock->shouldReceive('active')->once()->with(['foo'], 'bar', null)->andReturn('baz'); App::shouldReceive('make')->once()->with('active')->andReturn($activeMock); $result = active('foo', 'bar'); $this->assertEquals('baz', $result); } /** @test */ public function is_active_calls_is_active_method() { $activeMock = Mockery::mock(Active::class); $activeMock->shouldReceive('isActive')->once()->with(['foo'])->andReturn('bar'); App::shouldReceive('make')->once()->with('active')->andReturn($activeMock); $result = is_active('foo'); $this->assertEquals('bar', $result); } }