├── .gitignore ├── .travis.yml ├── DependencyInjection ├── Configuration.php └── WhiteOctoberBreadcrumbsExtension.php ├── LICENSE ├── Model ├── Breadcrumbs.php └── SingleBreadcrumb.php ├── README.md ├── Resources ├── config │ └── breadcrumbs.xml └── views │ ├── breadcrumbs.html.twig │ ├── json-ld.html.twig │ └── microdata.html.twig ├── Templating └── Helper │ └── BreadcrumbsHelper.php ├── Test ├── AppKernel.php ├── BundleTest.php ├── bootstrap.php └── config.xml ├── Twig └── Extension │ └── BreadcrumbsExtension.php ├── WhiteOctoberBreadcrumbsBundle.php ├── code-of-conduct.md ├── composer.json └── phpunit.xml /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | dist: trusty 4 | 5 | php: 6 | - 7.0 7 | - 7.1 8 | - 7.2 9 | - 7.3 10 | - 7.4snapshot 11 | 12 | matrix: 13 | include: 14 | - php: 7.1 15 | env: SYMFONY_VERSION=2.7.* 16 | - php: 7.1 17 | env: SYMFONY_VERSION=2.8.* 18 | - php: 7.1 19 | env: SYMFONY_VERSION=3.4.* 20 | - php: 7.1 21 | env: SYMFONY_VERSION="4.1.*" 22 | - php: 7.1 23 | env: SYMFONY_VERSION="4.2.*" 24 | 25 | sudo: false 26 | 27 | cache: 28 | directories: 29 | - $HOME/.composer/cache/files 30 | 31 | before_install: 32 | - composer self-update 33 | - if [ "$SYMFONY_VERSION" != "" ]; then composer require --dev --no-update symfony/symfony=$SYMFONY_VERSION; fi 34 | - INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; 35 | - echo memory_limit = -1 >> $INI_FILE 36 | 37 | install: 38 | - composer install 39 | 40 | script: 41 | - vendor/bin/phpunit 42 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode(); 21 | } else { 22 | // BC layer for symfony/config 4.1 and older 23 | $rootNode = $treeBuilder->root("white_october_breadcrumbs"); 24 | } 25 | 26 | $rootNode-> 27 | children()-> 28 | scalarNode("separator")->defaultValue("/")->end()-> 29 | scalarNode("separatorClass")->defaultValue("separator")->end()-> 30 | scalarNode("listId")->defaultValue("wo-breadcrumbs")->end()-> 31 | scalarNode("listClass")->defaultValue("breadcrumb")->end()-> 32 | scalarNode("itemClass")->defaultValue("")->end()-> 33 | scalarNode("linkRel")->defaultValue("")->end()-> 34 | scalarNode("locale")->defaultNull()->end()-> 35 | scalarNode("translation_domain")->defaultNull()->end()-> 36 | scalarNode("viewTemplate")->defaultValue("WhiteOctoberBreadcrumbsBundle::microdata.html.twig")->end()-> 37 | end() 38 | ; 39 | 40 | return $treeBuilder; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DependencyInjection/WhiteOctoberBreadcrumbsExtension.php: -------------------------------------------------------------------------------- 1 | loadConfiguration($configs, $container); 22 | 23 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 24 | $loader->load('breadcrumbs.xml'); 25 | } 26 | 27 | /** 28 | * Loads the configuration in, with any defaults 29 | * 30 | * @param array $configs 31 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container 32 | */ 33 | protected function loadConfiguration(array $configs, ContainerBuilder $container) 34 | { 35 | $configuration = new Configuration(); 36 | $config = $this->processConfiguration($configuration, $configs); 37 | 38 | if($config['viewTemplate'] === 'WhiteOctoberBreadcrumbsBundle::breadcrumbs.html.twig') { 39 | trigger_error( 40 | 'Using viewTemplate "'.$config['viewTemplate'].'"" is deprecated and should be replaced by ' . 41 | '"WhiteOctoberBreadcrumbsBundle::microdata.html.twig"', 42 | E_USER_DEPRECATED 43 | ); 44 | } 45 | 46 | $container->setParameter("white_october_breadcrumbs.options", $config); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012 White October Ltd 2 | http://www.whiteoctober.co.uk/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Model/Breadcrumbs.php: -------------------------------------------------------------------------------- 1 | array() 13 | ); 14 | 15 | /** 16 | * @var RouterInterface 17 | */ 18 | private $router; 19 | 20 | /** 21 | * @param string $text #TranslationKey 22 | */ 23 | public function addItem($text, $url = "", array $translationParameters = array(), $translate = true) 24 | { 25 | return $this->addNamespaceItem(self::DEFAULT_NAMESPACE, $text, $url, $translationParameters, $translate); 26 | } 27 | 28 | /** 29 | * @param string $text #TranslationKey 30 | */ 31 | public function addNamespaceItem($namespace, $text, $url = "", array $translationParameters = array(), $translate = true) 32 | { 33 | $b = new SingleBreadcrumb($text, $url, $translationParameters, $translate); 34 | $this->breadcrumbs[$namespace][] = $b; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * @param string $text #TranslationKey 41 | */ 42 | public function prependItem($text, $url = "", array $translationParameters = array(), $translate = true) 43 | { 44 | return $this->prependNamespaceItem(self::DEFAULT_NAMESPACE, $text, $url, $translationParameters, $translate); 45 | } 46 | 47 | /** 48 | * @param string $text #TranslationKey 49 | */ 50 | public function prependNamespaceItem($namespace, $text, $url = "", array $translationParameters = array(), $translate = true) 51 | { 52 | $b = new SingleBreadcrumb($text, $url, $translationParameters, $translate); 53 | array_unshift($this->breadcrumbs[$namespace], $b); 54 | 55 | return $this; 56 | } 57 | 58 | /** 59 | * @param string $text #TranslationKey 60 | * @param string $route #Route 61 | */ 62 | public function addRouteItem($text, $route, array $parameters = array(), $referenceType = RouterInterface::ABSOLUTE_PATH, array $translationParameters = array(), $translate = true) 63 | { 64 | return $this->addNamespaceRouteItem(self::DEFAULT_NAMESPACE, $text, $route, $parameters, $referenceType, $translationParameters, $translate); 65 | } 66 | 67 | /** 68 | * @param string $text #TranslationKey 69 | * @param string $route #Route 70 | */ 71 | public function addNamespaceRouteItem($namespace, $text, $route, array $parameters = array(), $referenceType = RouterInterface::ABSOLUTE_PATH, array $translationParameters = array(), $translate = true) 72 | { 73 | $url = $this->router->generate($route, $parameters, $referenceType); 74 | 75 | return $this->addNamespaceItem($namespace, $text, $url, $translationParameters, $translate); 76 | } 77 | 78 | /** 79 | * @param string $text #TranslationKey 80 | * @param string $route #Route 81 | */ 82 | public function prependRouteItem($text, $route, array $parameters = array(), $referenceType = RouterInterface::ABSOLUTE_PATH, array $translationParameters = array(), $translate = true) 83 | { 84 | return $this->prependNamespaceRouteItem(self::DEFAULT_NAMESPACE, $text, $route, $parameters, $referenceType, $translationParameters, $translate); 85 | } 86 | 87 | /** 88 | * @param string $text #TranslationKey 89 | * @param string $route #Route 90 | */ 91 | public function prependNamespaceRouteItem($namespace, $text, $route, array $parameters = array(), $referenceType = RouterInterface::ABSOLUTE_PATH, array $translationParameters = array(), $translate = true) 92 | { 93 | $url = $this->router->generate($route, $parameters, $referenceType); 94 | 95 | return $this->prependNamespaceItem($namespace, $text, $url, $translationParameters, $translate); 96 | } 97 | 98 | /** 99 | * @param string $text #TranslationKey 100 | */ 101 | public function addObjectArray(array $objects, $text, $url = "", array $translationParameters = array(), $translate = true) 102 | { 103 | return $this->addNamespaceObjectArray(self::DEFAULT_NAMESPACE, $objects, $text, $url, $translationParameters, $translate); 104 | } 105 | 106 | /** 107 | * @param string $text #TranslationKey 108 | */ 109 | public function addNamespaceObjectArray($namespace, array $objects, $text, $url = "", array $translationParameters = array(), $translate = true) 110 | { 111 | foreach($objects as $object) { 112 | $itemText = $this->validateArgument($object, $text); 113 | if ($url != "") { 114 | $itemUrl = $this->validateArgument($object, $url); 115 | } else { 116 | $itemUrl = ""; 117 | } 118 | $this->addNamespaceItem($namespace, $itemText, $itemUrl, $translationParameters, $translate); 119 | } 120 | 121 | return $this; 122 | } 123 | 124 | public function clear($namespace = "") 125 | { 126 | if (strlen($namespace)) { 127 | $this->breadcrumbs[$namespace] = array(); 128 | } else { 129 | $this->breadcrumbs = array( 130 | self::DEFAULT_NAMESPACE => array() 131 | ); 132 | } 133 | 134 | return $this; 135 | } 136 | 137 | /** 138 | * @param string $text #TranslationKey 139 | */ 140 | public function addObjectTree($object, $text, $url = "", $parent = 'parent', array $translationParameters = array(), $firstPosition = -1) 141 | { 142 | return $this->addNamespaceObjectTree(self::DEFAULT_NAMESPACE, $object, $text, $url, $parent, $translationParameters, $firstPosition); 143 | } 144 | 145 | /** 146 | * @param string $text #TranslationKey 147 | */ 148 | public function addNamespaceObjectTree($namespace, $object, $text, $url = "", $parent = 'parent', array $translationParameters = array(), $firstPosition = -1) 149 | { 150 | $itemText = $this->validateArgument($object, $text); 151 | if ($url != "") { 152 | $itemUrl = $this->validateArgument($object, $url); 153 | } else { 154 | $itemUrl = ""; 155 | } 156 | $itemParent = $this->validateArgument($object, $parent); 157 | if ($firstPosition == -1) { 158 | $firstPosition = sizeof($this->breadcrumbs); 159 | } 160 | $b = new SingleBreadcrumb($itemText, $itemUrl, $translationParameters); 161 | array_splice($this->breadcrumbs[$namespace], $firstPosition, 0, array($b)); 162 | if ($itemParent) { 163 | $this->addNamespaceObjectTree($namespace, $itemParent, $text, $url, $parent, $translationParameters, $firstPosition); 164 | } 165 | return $this; 166 | } 167 | 168 | public function getNamespaceBreadcrumbs($namespace = self::DEFAULT_NAMESPACE) 169 | { 170 | // Check whether requested namespace breadcrumbs is exists 171 | if (!$this->hasNamespaceBreadcrumbs($namespace)) { 172 | throw new \InvalidArgumentException(sprintf( 173 | 'The breadcrumb namespace "%s" does not exist', $namespace 174 | )); 175 | } 176 | 177 | return $this->breadcrumbs[$namespace]; 178 | } 179 | 180 | /** 181 | * @param string $namespace 182 | * @return bool 183 | */ 184 | public function hasNamespaceBreadcrumbs($namespace = self::DEFAULT_NAMESPACE) 185 | { 186 | return isset($this->breadcrumbs[$namespace]); 187 | } 188 | 189 | /** 190 | * @param RouterInterface $router 191 | */ 192 | public function setRouter(RouterInterface $router) 193 | { 194 | $this->router = $router; 195 | } 196 | 197 | public function rewind($namespace = self::DEFAULT_NAMESPACE) 198 | { 199 | return reset($this->breadcrumbs[$namespace]); 200 | } 201 | 202 | public function current($namespace = self::DEFAULT_NAMESPACE) 203 | { 204 | return current($this->breadcrumbs[$namespace]); 205 | } 206 | 207 | public function key($namespace = self::DEFAULT_NAMESPACE) 208 | { 209 | return key($this->breadcrumbs[$namespace]); 210 | } 211 | 212 | public function next($namespace = self::DEFAULT_NAMESPACE) 213 | { 214 | return next($this->breadcrumbs[$namespace]); 215 | } 216 | 217 | public function valid($namespace = self::DEFAULT_NAMESPACE) 218 | { 219 | return null !== key($this->breadcrumbs[$namespace]); 220 | } 221 | 222 | public function offsetExists($offset, $namespace = self::DEFAULT_NAMESPACE) 223 | { 224 | return isset($this->breadcrumbs[$namespace][$offset]); 225 | } 226 | 227 | public function offsetSet($offset, $value, $namespace = self::DEFAULT_NAMESPACE) 228 | { 229 | $this->breadcrumbs[$namespace][$offset] = $value; 230 | } 231 | 232 | public function offsetGet($offset, $namespace = self::DEFAULT_NAMESPACE) 233 | { 234 | return isset($this->breadcrumbs[$namespace][$offset]) ? $this->breadcrumbs[$namespace][$offset] : null; 235 | } 236 | 237 | public function offsetUnset($offset, $namespace = self::DEFAULT_NAMESPACE) 238 | { 239 | unset($this->breadcrumbs[$namespace][$offset]); 240 | } 241 | 242 | public function count($namespace = self::DEFAULT_NAMESPACE) 243 | { 244 | return count($this->breadcrumbs[$namespace]); 245 | } 246 | 247 | private function validateArgument($object, $argument) 248 | { 249 | if (is_callable($argument)) { 250 | return $argument($object); 251 | } 252 | 253 | $getter = 'get' . ucfirst($argument); 254 | if (method_exists($object, $getter)) { 255 | return call_user_func(array(&$object, $getter), $getter); 256 | } 257 | 258 | throw new \InvalidArgumentException(sprintf( 259 | 'Neither a valid callback function passed nor a method with the name %s() is exists', $getter 260 | )); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /Model/SingleBreadcrumb.php: -------------------------------------------------------------------------------- 1 | url = $url; 15 | $this->text = $text; 16 | $this->translationParameters = $translationParameters; 17 | $this->translate = $translate; 18 | } 19 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > WARNING: This project is **no longer maintained**. 2 | > If you are using it with Symfony >= 4.3, you may want to use [this fork](https://github.com/mhujer/BreadcrumbsBundle) instead. 3 | 4 | Installation 5 | ============ 6 | 7 | 1. Configure templating for your application if you haven't already. For example: 8 | 9 | ```yaml 10 | # app/config/config.yml (Symfony <=3) 11 | framework: 12 | templating: 13 | engines: ['twig'] 14 | 15 | # config/packages/framework.yaml (Symfony 4) 16 | templating: 17 | engines: ['twig'] 18 | ``` 19 | 20 | 2. Install this bundle using [Composer](https://getcomposer.org/): 21 | 22 | ``` bash 23 | composer require whiteoctober/breadcrumbs-bundle 24 | ``` 25 | 26 | 3. Add this bundle to your application's kernel: 27 | 28 | ``` php 29 | // app/AppKernel.php 30 | public function registerBundles() 31 | { 32 | $bundles = array( 33 | // ... 34 | new WhiteOctober\BreadcrumbsBundle\WhiteOctoberBreadcrumbsBundle(), 35 | // ... 36 | ); 37 | } 38 | ``` 39 | 40 | If you're using Symfony 4, this step will be done for you by Symfony Flex. 41 | 42 | 4. Configure the bundle in your config: 43 | 44 | ``` yaml 45 | # app/config/config.yml 46 | white_october_breadcrumbs: ~ 47 | ``` 48 | 49 | That's it for basic configuration. For more options check the [Configuration](#configuration) section. 50 | 51 | Usage 52 | ===== 53 | 54 | In your application controller methods: 55 | 56 | ``` php 57 | public function yourAction(User $user) 58 | { 59 | $breadcrumbs = $this->get("white_october_breadcrumbs"); 60 | 61 | // Simple example 62 | $breadcrumbs->addItem("Home", $this->get("router")->generate("index")); 63 | 64 | // Example without URL 65 | $breadcrumbs->addItem("Some text without link"); 66 | 67 | // Example with parameter injected into translation "user.profile" 68 | $breadcrumbs->addItem($txt, $url, ["%user%" => $user->getName()]); 69 | } 70 | ``` 71 | 72 | For Symfony 4, don't retrieve the service via `get`, instead use 73 | [dependency injection](https://symfony.com/doc/current/service_container.html#fetching-and-using-services): 74 | 75 | ```php 76 | use WhiteOctober\BreadcrumbsBundle\Model\Breadcrumbs; 77 | 78 | class YourController extends AbstractController 79 | { 80 | public function yourAction(Breadcrumbs $breadcrumbs) 81 | { 82 | // ... 83 | } 84 | } 85 | ``` 86 | 87 | 88 | Then, in your template: 89 | 90 | ``` jinja 91 | {{ wo_render_breadcrumbs() }} 92 | ``` 93 | 94 | The last item in the breadcrumbs collection will automatically be rendered 95 | as plain text rather than a `...` tag. 96 | 97 | The `addItem()` method adds an item to the *end* of the breadcrumbs collection. 98 | You can use the `prependItem()` method to add an item to the *beginning* of 99 | the breadcrumbs collection. This is handy when used in conjunction with 100 | hierarchical data (e.g. Doctrine Nested-Set). This example uses categories in 101 | a product catalog: 102 | 103 | ``` php 104 | public function yourAction(Category $category) 105 | { 106 | $breadcrumbs = $this->get("white_october_breadcrumbs"); 107 | 108 | $node = $category; 109 | 110 | while ($node) { 111 | $breadcrumbs->prependItem($node->getName(), ""); 112 | 113 | $node = $node->getParent(); 114 | } 115 | } 116 | ``` 117 | 118 | If you do not want to generate a URL manually, you can easily add breadcrumb items 119 | passing only the route name with any required parameters, using the `addRouteItem()` 120 | and `prependRouteItem()` methods: 121 | 122 | ``` php 123 | public function yourAction() 124 | { 125 | $breadcrumbs = $this->get("white_october_breadcrumbs"); 126 | 127 | // Pass "_demo" route name without any parameters 128 | $breadcrumbs->addRouteItem("Demo", "_demo"); 129 | 130 | // Pass "_demo_hello" route name with route parameters 131 | $breadcrumbs->addRouteItem("Hello Breadcrumbs", "_demo_hello", [ 132 | 'name' => 'Breadcrumbs', 133 | ]); 134 | 135 | // Add "homepage" route link at the start of the breadcrumbs 136 | $breadcrumbs->prependRouteItem("Home", "homepage"); 137 | } 138 | ``` 139 | 140 | Configuration 141 | ============= 142 | 143 | The following *default* parameters can be overriden in your `config.yml` or similar: 144 | 145 | ``` yaml 146 | # app/config/config.yml 147 | white_october_breadcrumbs: 148 | separator: '/' 149 | separatorClass: 'separator' 150 | listId: 'wo-breadcrumbs' 151 | listClass: 'breadcrumb' 152 | itemClass: '' 153 | linkRel: '' 154 | locale: ~ # defaults to null, so the default locale is used 155 | translation_domain: ~ # defaults to null, so the default domain is used 156 | viewTemplate: 'WhiteOctoberBreadcrumbsBundle::microdata.html.twig' 157 | ``` 158 | 159 | These can also be passed as parameters in the view when rendering the 160 | breadcrumbs - for example: 161 | 162 | ``` jinja 163 | {{ wo_render_breadcrumbs({separator: '>', listId: 'breadcrumbs'}) }} 164 | ``` 165 | 166 | > **NOTE:** If you need more than one set of breadcrumbs on the same page you can use namespaces. 167 | By default, breadcrumbs use the `default` namespace, but you can add more. 168 | To add breadcrumbs to your custom namespace use `addNamespaceItem` / `prependNamespaceItem` 169 | or `addNamespaceRouteItem` / `prependNamespaceRouteItem` methods respectively, for example: 170 | 171 | ``` php 172 | public function yourAction(User $user) 173 | { 174 | $breadcrumbs = $this->get("white_october_breadcrumbs"); 175 | 176 | // Simple example 177 | $breadcrumbs->prependNamespaceItem("subsection", "Home", $this->get("router")->generate("index")); 178 | 179 | // Example without URL 180 | $breadcrumbs->addNamespaceItem("subsection", "Some text without link"); 181 | 182 | // Example with parameter injected into translation "user.profile" 183 | $breadcrumbs->addNamespaceItem("subsection", $txt, $url, ["%user%" => $user->getName()]); 184 | 185 | // Example with route name with required parameters 186 | $breadcrumbs->addNamespaceRouteItem("subsection", $user->getName(), "user_show", ["id" => $user->getId()]); 187 | } 188 | ``` 189 | 190 | Then to render the `subsection` breadcrumbs in your templates, specify this namespace in the options: 191 | 192 | ``` jinja 193 | {{ wo_render_breadcrumbs({namespace: "subsection"}) }} 194 | ``` 195 | 196 | Advanced Usage 197 | ============== 198 | 199 | You can add a whole array of objects at once 200 | 201 | ``` php 202 | $breadcrumbs->addObjectArray(array $objects, $text, $url, $translationParameters); 203 | ``` 204 | 205 | ``` 206 | objects: array of objects 207 | text: name of object property or closure 208 | url: name of URL property or closure 209 | ``` 210 | 211 | Example: 212 | 213 | ``` php 214 | $that = $this; 215 | $breadcrumbs->addObjectArray($selectedPath, "name", function($object) use ($that) { 216 | return $that->generateUrl('_object_index', ['slug' => $object->getSlug()]); 217 | }); 218 | ``` 219 | 220 | You can also add a tree path 221 | 222 | ``` php 223 | $breadcrumbs->addObjectTree($object, $text, $url = "", $parent = 'parent', array $translationParameters = [], $firstPosition = -1) 224 | ``` 225 | 226 | ``` 227 | object: object to start with 228 | text: name of object property or closure 229 | url: name of URL property or closure 230 | parent: name of parent property or closure 231 | firstPosition: position to start inserting items (-1 = determine automatically) 232 | ``` 233 | 234 | > **NOTE:** You can use `addNamespaceObjectArray` and `addNamespaceObjectTree` respectively 235 | for work with multiple breadcrumbs on the same page. 236 | 237 | Overriding the template 238 | ======================= 239 | 240 | There are two methods for doing this. 241 | 242 | 1. You can override the template used by copying the 243 | `Resources/views/microdata.html.twig` file out of the bundle and placing it 244 | into `app/Resources/WhiteOctoberBreadcrumbsBundle/views`, then customising 245 | as you see fit. Check the [Overriding bundle templates][1] documentation section 246 | for more information. 247 | 248 | 2. Use the `viewTemplate` configuration parameter: 249 | 250 | ``` jinja 251 | {{ wo_render_breadcrumbs({ viewTemplate: "YourOwnBundle::yourBreadcrumbs.html.twig" }) }} 252 | ``` 253 | > **NOTE:** If you want to use the JSON-LD format, there's already an existing template 254 | at `WhiteOctoberBreadcrumbsBundle::json-ld.html.twig`. Just set this template as the value for 255 | `viewTemplate` either in your Twig function call (see Step 2 above) or in your bundle [configuration](#configuration). 256 | 257 | 258 | 259 | [1]: http://symfony.com/doc/current/book/templating.html#overriding-bundle-templates 260 | [2]: https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx 261 | 262 | 263 | _(This project was originally at https://github.com/whiteoctober/BreadcrumbsBundle)_ 264 | -------------------------------------------------------------------------------- /Resources/config/breadcrumbs.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | %white_october_breadcrumbs.options% 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Resources/views/breadcrumbs.html.twig: -------------------------------------------------------------------------------- 1 | {% include "WhiteOctoberBreadcrumbsBundle::microdata.html.twig" %} 2 | -------------------------------------------------------------------------------- /Resources/views/json-ld.html.twig: -------------------------------------------------------------------------------- 1 | {% if wo_breadcrumbs()|length %} 2 | {% apply spaceless %} 3 | 23 | {% endapply %} 24 | {% endif %} 25 | -------------------------------------------------------------------------------- /Resources/views/microdata.html.twig: -------------------------------------------------------------------------------- 1 | {% if wo_breadcrumbs()|length %} 2 | {% apply spaceless %} 3 |
    4 | {% for b in breadcrumbs %} 5 | 6 | {% if b.url and not loop.last %} 7 | 8 | {% endif %} 9 | {% if b.translate is defined and b.translate == true %}{{- b.text | trans(b.translationParameters, translation_domain, locale) -}}{% else %}{{- b.text -}}{% endif %} 10 | {% if b.url and not loop.last %} 11 | 12 | {% elseif b.url %} 13 | 14 | {% endif %} 15 | 16 | 17 | {% if separator is not null and not loop.last %} 18 | {{ separator }} 19 | {% endif %} 20 | 21 | {% endfor %} 22 |
23 | {% endapply %} 24 | {% endif %} 25 | -------------------------------------------------------------------------------- /Templating/Helper/BreadcrumbsHelper.php: -------------------------------------------------------------------------------- 1 | templating = $templating; 34 | $this->breadcrumbs = $breadcrumbs; 35 | $this->options = array_merge($options, array( 36 | 'namespace' => Breadcrumbs::DEFAULT_NAMESPACE, // inject default namespace to options 37 | )); 38 | } 39 | 40 | /** 41 | * Returns the HTML for the namespace breadcrumbs 42 | * 43 | * @param array $options The user-supplied options from the view 44 | * @return string A HTML string 45 | */ 46 | public function breadcrumbs(array $options = array()) 47 | { 48 | $options = $this->resolveOptions($options); 49 | 50 | // Assign namespace breadcrumbs 51 | $options["breadcrumbs"] = $this->breadcrumbs->getNamespaceBreadcrumbs($options['namespace']); 52 | 53 | return $this->templating->render( 54 | $options["viewTemplate"], 55 | $options 56 | ); 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | * @codeCoverageIgnore 62 | */ 63 | public function getName() 64 | { 65 | return 'breadcrumbs'; 66 | } 67 | 68 | /** 69 | * Merges user-supplied options from the view 70 | * with base config values 71 | * 72 | * @param array $options The user-supplied options from the view 73 | * @return array 74 | */ 75 | private function resolveOptions(array $options = array()) 76 | { 77 | return array_merge($this->options, $options); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Test/AppKernel.php: -------------------------------------------------------------------------------- 1 | cachePrefix = $cachePrefix; 34 | $this->addBundle(FrameworkBundle::class); 35 | $this->addConfigFile(__DIR__.'/config.xml'); 36 | $this->addConfigFile(__DIR__.'/../Resources/config/breadcrumbs.xml'); 37 | } 38 | 39 | public function addBundle($bundleClassName) 40 | { 41 | $this->bundlesToRegister[] = $bundleClassName; 42 | } 43 | 44 | public function registerBundles() 45 | { 46 | $this->bundlesToRegister = array_unique($this->bundlesToRegister); 47 | $bundles = []; 48 | foreach ($this->bundlesToRegister as $bundle) { 49 | $bundles[] = new $bundle(); 50 | } 51 | 52 | return $bundles; 53 | } 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function registerContainerConfiguration(LoaderInterface $loader) 58 | { 59 | $loader->load(function (ContainerBuilder $container) use ($loader) { 60 | $this->configFiles = array_unique($this->configFiles); 61 | foreach ($this->configFiles as $path) { 62 | $loader->load($path); 63 | } 64 | 65 | $container->addObjectResource($this); 66 | $container->setParameter('white_october_breadcrumbs.options', []); 67 | }); 68 | } 69 | /** 70 | * @param string $configFile path to config file 71 | */ 72 | public function addConfigFile($configFile) 73 | { 74 | $this->configFiles[] = $configFile; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Test/BundleTest.php: -------------------------------------------------------------------------------- 1 | getContainer(); 15 | 16 | // Test if the service exists 17 | $this->assertTrue($container->has('white_october_breadcrumbs.helper')); 18 | 19 | $service = $container->get('white_october_breadcrumbs.helper'); 20 | $this->assertInstanceOf(\WhiteOctober\BreadcrumbsBundle\Templating\Helper\BreadcrumbsHelper::class, $service); 21 | } 22 | 23 | public static function getKernelClass() 24 | { 25 | return \WhiteOctober\BreadcrumbsBundle\Test\AppKernel::class; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Test/bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | php 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Twig/Extension/BreadcrumbsExtension.php: -------------------------------------------------------------------------------- 1 | container = $container; 20 | $this->breadcrumbs = $container->get("white_october_breadcrumbs"); 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function getFunctions() 27 | { 28 | return array( 29 | new \Twig_SimpleFunction("wo_breadcrumbs", array($this, "getBreadcrumbs")), 30 | new \Twig_SimpleFunction("wo_breadcrumbs_exists", array($this, "hasBreadcrumbs")), 31 | new \Twig_SimpleFunction("wo_render_breadcrumbs", array($this, "renderBreadcrumbs"), array("is_safe" => array("html"))), 32 | ); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function getFilters() 39 | { 40 | return array( 41 | new \Twig_SimpleFilter("wo_is_final_breadcrumb", array($this, "isLastBreadcrumb")), 42 | ); 43 | } 44 | 45 | /** 46 | * Returns the breadcrumbs object 47 | * 48 | * @param string $namespace 49 | * @return \WhiteOctober\BreadcrumbsBundle\Model\Breadcrumbs 50 | */ 51 | public function getBreadcrumbs($namespace = Breadcrumbs::DEFAULT_NAMESPACE) 52 | { 53 | return $this->breadcrumbs->getNamespaceBreadcrumbs($namespace); 54 | } 55 | 56 | /** 57 | * @param string $namespace 58 | * @return bool 59 | */ 60 | public function hasBreadcrumbs($namespace = Breadcrumbs::DEFAULT_NAMESPACE) 61 | { 62 | return $this->breadcrumbs->hasNamespaceBreadcrumbs($namespace); 63 | } 64 | 65 | /** 66 | * Renders the breadcrumbs in a list 67 | * 68 | * @param array $options 69 | * @return string 70 | */ 71 | public function renderBreadcrumbs(array $options = array()) 72 | { 73 | return $this->container->get("white_october_breadcrumbs.helper")->breadcrumbs($options); 74 | } 75 | 76 | /** 77 | * Checks if this breadcrumb is the last one in the collection 78 | * 79 | * @param SingleBreadcrumb $crumb 80 | * @param string $namespace 81 | * @return bool 82 | */ 83 | public function isLastBreadcrumb(SingleBreadcrumb $crumb, $namespace = Breadcrumbs::DEFAULT_NAMESPACE) 84 | { 85 | $offset = $this->breadcrumbs->count($namespace) - 1; 86 | 87 | return $crumb === $this->breadcrumbs->offsetGet($offset, $namespace); 88 | } 89 | 90 | /** 91 | * {@inheritdoc} 92 | */ 93 | public function getName() 94 | { 95 | return "breadcrumbs"; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /WhiteOctoberBreadcrumbsBundle.php: -------------------------------------------------------------------------------- 1 | =5.3.2", 16 | "symfony/framework-bundle": "~2.0|~3.0|^4.0", 17 | "symfony/templating": "~2.7|~3.0|^4.0" 18 | }, 19 | "require-dev": { 20 | "phpunit/phpunit": "^6.4", 21 | "symfony/browser-kit": "~2.7|~3.0|^4.0" 22 | }, 23 | "abandoned": "mhujer/breadcrumbs-bundle", 24 | "autoload": { 25 | "psr-0": { "WhiteOctober\\BreadcrumbsBundle": "" } 26 | }, 27 | "target-dir": "WhiteOctober/BreadcrumbsBundle" 28 | } 29 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Test/ 7 | 8 | 9 | 10 | 11 | 12 | / 13 | 14 | 15 | 16 | --------------------------------------------------------------------------------