# Tag Manager Bundle #
Symfony2 Bundle to provide the management and rendering of tags. 


## Requirements ##
* PHP 5.4+
* Symfony v2.4+
* VisualMedia Block Manager Bundle
* VisualMedia Model Manager Bundle
* VisualMedia Management Layout Bundle
* VisualMedia DataExtractor Bundle


## Known issues / improvements ##
* Code editor for expressions is not optimized for editing the Symfony Expression Language
* Adding static data with ExtendedDataDictionary should be more configurable
* Adding extra tags in the controller should be posible 


## Important classes ##

* `VisualM\TagManagerBundle\Entity\MetaTagSet` Defines a set of presets that can be added to an content entity.

* `VisualM\TagManagerBundle\Entity\MetaTagPreset` Added in a set it defines the title, type and default settings for tags.

* `VisualM\TagManagerBundle\Entity\MetaTag` Coupled to content entities it extends the configuration from a tag preset.
 
* `VisualM\TagManagerBundle\Content\MetaHelper` Class used in the controller to collect object data and set the entity to render tags for. Also used for rendering the tags using the Twig proxy class

* `VisualM\TagManagerBundle\Util\ExtendedDataDictionary` Class that extends the DataCollector from the VisualMDataExtractBundle, supports static data.

* `VisualM\TagManagerBundle\Util\ExtendedExpressionLanguage` Class that extends the ExpressionLanguage class with some usefull methods (lowercase, uppercase, start, end and html).



## Basic configuration ##


### Assetic ###
Add the VisualMTagManagerBundle to the list of Assetic bundles 
	
	// app/config.yml

	...
	assetic:
	    bundles:        [ ..., VisualMTagManagerBundle  ]
	...




### Security roles ###
Add the following security roles to your configuration

* `ROLE_PERM_LIST_META_TAG_SET` Allow displaying list of Tag sets
* `ROLE_PERM_EDIT_META_TAG_SET` Allow editing of Tag set
* `ROLE_PERM_ADD_META_TAG_SET` Allow adding of Tag set
* `ROLE_PERM_DELETE_META_TAG_SET` Allow deleting of Tag set
* `ROLE_PERM_META_TAG_BEPERKT` Allow editing inhoud/zichtbaar for wijzigbaar = "Beperkt"


## Entity specific configuration ##
For each entity (or group of entities) you want the tag manager to configure the tags for.


### Implement TaggableContentInterface on your entity ###
The TaggableContentInterface adds two methods. The function `getContentId` should provide a unique identifier to this entity. Return null when no unqiue identifier is available (e.g. entity isn't stored yet). Make sure the identifier is unique accros all your entity classes. The functions `getMetaTagCollection` and `setMetaTagCollection` should set and retrieve an MetaTagCollection object. Initialisation of this object isn't required as it is set in the form. Also storage of this object isn't required it is used for the form that is coupled to the entity.
 

	// .../Entity/Object.php

	use Symfony\Component\Validator\Constraints as Assert;
	use VisualM\TagManagerBundle\Content\TaggableContentInterface;
	use VisualM\TagManagerBundle\Model\MetaTagCollection;

	...

	class Object implements TaggableContentInterface
	{
		...

		/**
	     * MetaTagCollection
	     * @var MetaTagCollection
	     * @Assert\Valid()
	     */
	    private $metaTagCollection;

		/**
	     * {@inheritDoc}
	     */
	    public function getContentId()
	    {
			// NOTE: The implementation of this function is object specific
			// this implementation is only a suggestion!
			
	        if ($this->getId() === null) {
	            return null;
	        } else {
	            return str_replace('Proxies\\__CG__\\', '', get_class($this)) . '#' . $this->getId();
	        }
	    }
	
	    /**
	     * {@inheritDoc}
	     */
	    public function getMetaTagCollection()
	    {
	        return $this->metaTagCollection;
	    }
	
	    /**
	     * {@inheritDoc}
	     */
	    public function setMetaTagCollection($metaTagCollection)
	    {
	        $this->metaTagCollection = $metaTagCollection;
	    }		

		...
	}

### Implement TaggableContentManagerInterface on the related Repository ###
The TaggableContentManagerInterface adds two methods. The first `getContentIds` should return an list of contentId's (see block above for meaning) that are managed by this repository. The second function `isEntityHandled` should return a boolean if the repository manages the given object.
 

	// .../Entity/ObjectRepository.php

	use VisualM\TagManagerBundle\Content\TaggableContentInterface;
	use VisualM\TagManagerBundle\Content\TaggableContentManagerInterface;

	...

	class ObjectRepository implements TaggableContentManagerInterface
	{

		...

	    /**
	     * {@inheritDoc}
	     */
	    public function getContentIds()
	    {
			// NOTE: The implementation of this function is object specific
			// this implementation is only a suggestion!

	        $content_ids = [];
	        foreach($this->getIndex() as $pagina) {
	            $content_ids[] = $pagina->getContentId();
	        }
	        return $content_ids;
	    }
	
	    /**
	     * {@inheritDoc}
	     */
	    public function isEntityHandled(TaggableContentInterface $entity)
	    {
			// NOTE: The implementation of this function is object specific
			// this implementation is only a suggestion!

	        return ($entity instanceof Object);
	    }
	    
		...

	}

### Add repository as an tagged service ###
Tag the Repository that is created in the block above in the service definition with the tag `visualm.taggable.manager` with an extra attribute `content_name`. This content name is used in the tag set management for selecting for which content types the set is default for. Make sure that `content_name` is unique for each type of content.

	// ../Resources/config/services.yml

	... 

	example.manager.object:
        class: Doctrine\Common\Persistence\ObjectRepository
        factory_service: doctrine
        factory_method: getRepository
        arguments: [ 'ExampleBundle\Entity\Object' ]
        tags:
          - { name : 'visualm.taggable.manager', content_name : 'object' }

	...


## Adding a form for tag management ##
When you want to edit tags for a specific entity you can add it to the FormType associated with the entity and the view that is used for editing the entity


## Adding the field to the FormType ##

	// ../Form/Type/ObjectType.php

	...

	class GebruikerType extends AbstractType
	{

	...

	/**
     * {@inheritDoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
		...

		$builder->add('metaTagCollection', 'meta_tag_collection', [
            'content_name' => 'pagina'
        ]);

		...
	}

	...

## Adding the view needed for management ##

	// ../Resources/views/object/form.html.twig
	
	...

	{% include 'VisualMTagManagerBundle:ManageMetaTagCollection:form.html.twig' with { form : object_form.metaTagCollection } %}

	...


## Displaying Tags ##


### Set Content Item and Data in the Controller ###
To display Tags the system needs the data to be extracted from the correct entities. Also it needs to know the entity for which tags to render. Use `collectObject` to add data to the collection. (This is just a proxy method to `DataCollector::pushObject()`, see the VisualMDataExtractBundle for more information). Use `setContent` to set the object to render data for. This last function should only be called once. Any call to `setContent` will overwrite the earlier object provided.


	// ../Controller/ObjectController.php

	...

	class ObjectController extends Controller
	{

		...

		public function exampleAction()
		{
			// Retrieve the object
			$object = $ojectRepository->findById(1);

			$meta_helper = $this->get('visualm.tag_manager.content.meta_helper');
        	$meta_helper
				->collectObject($object)
				->collectObject($object->getVisuals()->first())
				->setContent($object);

		}

		...
	}

### Add the rendering functions to your layout ###
This functions use the data set in the constructor to determine which tags to render and returns the HTML for them. `meta_tags_header` add the tags to be rendered in the header and should be added to the end of the head section. `meta_tags_body` add the tags to be rendered in the body and should be added to the start of the body section. 


	// ../Resources/views/layout.html.twig

	

	<html>
		<head>

			...
	
			{{ meta_tags_header() }}

		</head>

		<body>

			{{ meta_tags_body() }}

			...

		</body>
	</html>
	

