Browse Source

Add Portfolio Tool - refs BT#14056

jmontoyaa 7 years ago
parent
commit
b256c09001

+ 19 - 0
app/config/portfolio.conf.php

@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * This file contains the portfolios configuration.
+ * 
+ * Portfolios are external applicatoins used to display and share files. The
+ * portfolio configuration set up where files can be sent.
+ * 
+ * @see \Portfolio
+ */
+
+$portfolios = array();
+
+//$_mahara_portfolio = new Portfolio\Mahara('http(s)://...');
+//$portfolios[] = $_mahara_portfolio;
+
+//$download_portfolio = new Portfolio\Download();
+//$download_portfolio->set_title(get_lang('Download'));
+//$portfolios[] = $download_portfolio;

BIN
main/img/icons/64/wiki_task_na.png


+ 41 - 0
main/portfolio/add_category.php

@@ -0,0 +1,41 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+use Chamilo\CoreBundle\Entity\PortfolioCategory;
+
+$form = new FormValidator('add_category', 'post', "$baseUrl&action=add_category");
+$form->addText('title', get_lang('Title'));
+$form->addHtmlEditor('description', get_lang('Description'), false, false, ['ToolbarSet' => 'Minimal']);
+$form->addButtonCreate(get_lang('Create'));
+
+if ($form->validate()) {
+    $values = $form->exportValues();
+
+    $category = new PortfolioCategory();
+    $category
+        ->setTitle($values['title'])
+        ->setDescription($values['description'])
+        ->setUser($user);
+
+    $em->persist($category);
+    $em->flush();
+
+    Display::addFlash(
+        Display::return_message(get_lang('CategoryAdded'), 'success')
+    );
+
+    header("Location: $baseUrl");
+    exit;
+}
+
+$toolName = get_lang('AddCategory');
+$interbreadcrumb[] = [
+    'name' => get_lang('Portfolio'),
+    'url' => $baseUrl,
+];
+
+$actions[] = Display::url(
+    Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM),
+    $baseUrl
+);
+$content = $form->returnForm();

+ 59 - 0
main/portfolio/add_item.php

@@ -0,0 +1,59 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+use Chamilo\CoreBundle\Entity\Portfolio;
+
+$categories = $em
+    ->getRepository('ChamiloCoreBundle:PortfolioCategory')
+    ->findBy([
+        'user' => $user,
+    ]);
+
+$form = new FormValidator('add_portfolio', 'post', $baseUrl.'action=add_item');
+$form->addText('title', get_lang('Title'));
+$form->addHtmlEditor('content', get_lang('Content'), true, false, ['ToolbarSet' => 'NotebookStudent']);
+$form->addSelectFromCollection('category', get_lang('Category'), $categories, [], true);
+$form->addButtonCreate(get_lang('Create'));
+
+if ($form->validate()) {
+    $values = $form->exportValues();
+    $currentTime = new DateTime(
+        api_get_utc_datetime(),
+        new DateTimeZone('UTC')
+    );
+
+    $portfolio = new Portfolio();
+    $portfolio
+        ->setTitle($values['title'])
+        ->setContent($values['content'])
+        ->setUser($user)
+        ->setCourse($course)
+        ->setSession($session)
+        ->setCategory(
+            $em->find('ChamiloCoreBundle:PortfolioCategory', $values['category'])
+        )
+        ->setCreationDate($currentTime)
+        ->setUpdateDate($currentTime);
+
+    $em->persist($portfolio);
+    $em->flush();
+
+    Display::addFlash(
+        Display::return_message(get_lang('PortfolioItemAdded'), 'success')
+    );
+
+    header("Location: $baseUrl");
+    exit;
+}
+
+$toolName = get_lang('AddPortfolioItem');
+$interbreadcrumb[] = [
+    'name' => get_lang('Portfolio'),
+    'url' => $baseUrl,
+];
+
+$actions[] = Display::url(
+    Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM),
+    $baseUrl
+);
+$content = $form->returnForm();

+ 40 - 0
main/portfolio/edit_category.php

@@ -0,0 +1,40 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+$form = new FormValidator('edit_category', 'post', $baseUrl."action=edit_category&id={$category->getId()}");
+$form->addText('title', get_lang('Title'));
+$form->addHtmlEditor('description', get_lang('Description'), false, false, ['ToolbarSet' => 'Minimal']);
+$form->addButtonUpdate(get_lang('Update'));
+$form->setDefaults([
+    'title' => $category->getTitle(),
+    'description' => $category->getDescription(),
+]);
+
+if ($form->validate()) {
+    $values = $form->exportValues();
+
+    $category
+        ->setTitle($values['title'])
+        ->setDescription($values['description']);
+
+    $em->persist($category);
+    $em->flush();
+
+    Display::addFlash(
+        Display::return_message(get_lang('Updated'), 'success')
+    );
+
+    header("Location: $baseUrl");
+    exit;
+}
+
+$toolName = get_lang('EditCategory');
+$interbreadcrumb[] = [
+    'name' => get_lang('Portfolio'),
+    'url' => $baseUrl,
+];
+$actions[] = Display::url(
+    Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM),
+    $baseUrl
+);
+$content = $form->returnForm();

+ 53 - 0
main/portfolio/edit_item.php

@@ -0,0 +1,53 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+$categories = $em
+    ->getRepository('ChamiloCoreBundle:PortfolioCategory')
+    ->findBy([
+        'user' => $user,
+    ]);
+
+$form = new FormValidator('edit_portfolio', 'post', $baseUrl."action=edit_item&id={$item->getId()}");
+$form->addText('title', get_lang('Title'));
+$form->addHtmlEditor('content', get_lang('Content'), true, false, ['ToolbarSet' => 'NotebookStudent']);
+$form->addSelectFromCollection('category', get_lang('Category'), $categories, [], true, '__toString');
+$form->addButtonUpdate(get_lang('Update'));
+$form->setDefaults([
+    'title' => $item->getTitle(),
+    'content' => $item->getContent(),
+    'category' => $item->getCategory() ? $item->getCategory()->getId() : '',
+]);
+
+if ($form->validate()) {
+    $values = $form->exportValues();
+    $currentTime = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
+
+    $item
+        ->setTitle($values['title'])
+        ->setContent($values['content'])
+        ->setUpdateDate($currentTime)
+        ->setCategory(
+            $em->find('ChamiloCoreBundle:PortfolioCategory', $values['category'])
+        );
+
+    $em->persist($item);
+    $em->flush();
+
+    Display::addFlash(
+        Display::return_message(get_lang('Updated'), 'success')
+    );
+
+    header("Location: $baseUrl");
+    exit;
+}
+
+$toolName = get_lang('EditPortfolioItem');
+$interbreadcrumb[] = [
+    'name' => get_lang('Portfolio'),
+    'url' => $baseUrl,
+];
+$actions[] = Display::url(
+    Display::return_icon('back.png', get_lang('Back'), [], ICON_SIZE_MEDIUM),
+    $baseUrl
+);
+$content = $form->returnForm();

+ 59 - 0
main/portfolio/list.php

@@ -0,0 +1,59 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+if ($currentUserId == $user->getId()) {
+    if ($allowEdit) {
+        $actions[] = Display::url(
+            Display::return_icon('add.png', get_lang('Add'), [], ICON_SIZE_MEDIUM),
+            $baseUrl.'action=add_item'
+        );
+        $actions[] = Display::url(
+            Display::return_icon('folder.png', get_lang('AddCategory'), [], ICON_SIZE_MEDIUM),
+            $baseUrl.'action=add_category'
+        );
+        $actions[] = Display::url(
+            Display::return_icon('shared_setting.png', get_lang('Preview'), [], ICON_SIZE_MEDIUM),
+            $baseUrl.'preview=&user='.$user->getId()
+        );
+    } else {
+        $actions[] = Display::url(
+            Display::return_icon('shared_setting_na.png', get_lang('Preview'), [], ICON_SIZE_MEDIUM),
+            $baseUrl
+        );
+    }
+}
+
+$form = new FormValidator('a');
+$form->addUserAvatar('user', get_lang('User'), 'medium');
+$form->setDefaults(['user' => $user]);
+
+$criteria = ['user' => $user];
+
+if (!$allowEdit) {
+    $criteria['isVisible'] = true;
+}
+
+$categories = $em
+    ->getRepository('ChamiloCoreBundle:PortfolioCategory')
+    ->findBy($criteria);
+
+if ($course) {
+    $criteria['course'] = $course;
+    $criteria['session'] = $session;
+}
+
+$criteria['category'] = null;
+
+$items = $em
+    ->getRepository('ChamiloCoreBundle:Portfolio')
+    ->findBy($criteria);
+
+$template = new Template(null, false, false, false, false, false, false);
+$template->assign('user', $user);
+$template->assign('course', $course);
+$template->assign('session', $session);
+$template->assign('allow_edit', $allowEdit);
+$template->assign('portfolio', $categories);
+$template->assign('uncategorized_items', $items);
+$layout = $template->get_template('portfolio/list.html.twig');
+$content = $template->fetch($layout);

+ 67 - 0
main/template/default/portfolio/items.html.twig

@@ -0,0 +1,67 @@
+{% macro display(items, category_id, allow_edit, _c) %}
+    {% set edit_img = 'edit.png'|img(22, 'Edit'|get_lang) %}
+    {% set visible_img = 'visible.png'|img(22, 'Invisible'|get_lang) %}
+    {% set invisible_img = 'invisible.png'|img(22, 'Visible'|get_lang) %}
+    {% set delete_img = 'delete.png'|img(22, 'Delete'|get_lang) %}
+    {% set baseurl = _p.web_self ~ '?' ~ (_p.web_cid_query ? _p.web_cid_query ~ '&' : '') %}
+
+    <div class="panel-group" id="accordion-list-{{ category_id }}" role="tablist" aria-multiselectable="true">
+        {% for item in items %}
+            <div class="panel panel-default">
+                <div class="panel-heading" role="tab" id="heading-item-{{ item.id }}">
+                    {% if allow_edit %}
+                        <div class="pull-right">
+                            <a href="{{ baseurl ~ {'action':'edit_item', 'id':item.id}|url_encode }}">
+                                {{ edit_img }}
+                            </a>
+                            {% if item.isVisible %}
+                                <a href="{{ baseurl ~ {'action':'hide_item', 'id':item.id}|url_encode }}">
+                                    {{ visible_img }}
+                                </a>
+                            {% else %}
+                                <a href="{{ baseurl ~ {'action':'show_item', 'id':item.id}|url_encode }}">
+                                    {{ invisible_img }}
+                                </a>
+                            {% endif %}
+                            <a href="{{ baseurl ~ {'action':'delete_item', 'id':item.id}|url_encode }}"
+                               class="btn-delete">
+                                {{ delete_img }}
+                            </a>
+                        </div>
+                    {% endif %}
+                    <h5 class="panel-title">
+                        <a href="#collapse-{{ item.id }}" class="collapsed" role="button"
+                           data-parent="#accordion-list-{{ category_id }}"
+                           data-toggle="collapse" aria-expanded="false" aria-controls="collapse-{{ item.id }}">
+                            {{ item.title }}
+                        </a>
+                    </h5>
+                    {% if _c is empty %}
+                        {% if item.session %}
+                            <div class="clearfix">
+                                {{ 'Course'|get_lang ~ ': ' ~ item.session.name ~ ' (' ~ item.course.title ~ ')' }}
+                            </div>
+                        {% elseif not item.session and item.course %}
+                            <div class="clearfix">
+                                {{ 'Course'|get_lang ~ ': ' ~ item.course.title }}<br>
+                            </div>
+                        {% endif %}
+                    {% endif %}
+                </div>
+                <div id="collapse-{{ item.id }}" class="panel-collapse collapse" role="tabpanel"
+                     aria-labelledby="heading-item-{{ item.id }}">
+                    <div class="panel-body">
+                        {{ item.content }}
+                    </div>
+                </div>
+                <div class="panel-footer">
+                    {{ 'CreationDate'|get_lang ~ ': ' ~ item.creationDate|api_convert_and_format_date(6) }}
+                    {% if item.creationDate != item.updateDate %}
+                        &centerdot;
+                        {{ 'UpdateDate'|get_lang ~ ': ' ~ item.updateDate|api_convert_and_format_date(6) }}
+                    {% endif %}
+                </div>
+            </div>
+        {% endfor %}
+    </div>
+{% endmacro %}

+ 65 - 0
main/template/default/portfolio/list.html.twig

@@ -0,0 +1,65 @@
+{% set edit_img = 'edit.png'|img(22, 'Edit'|get_lang) %}
+{% set visible_img = 'visible.png'|img(22, 'Invisible'|get_lang) %}
+{% set invisible_img = 'invisible.png'|img(22, 'Visible'|get_lang) %}
+{% set delete_img = 'delete.png'|img(22, 'Delete'|get_lang) %}
+{% set baseurl = _p.web_self ~ '?' ~ (_p.web_cid_query ? _p.web_cid_query ~ '&' : '') %}
+
+{% import template ~ '/portfolio/items.html.twig' as items %}
+
+{% if not allow_edit %}
+    <h3>{{ user.completeName }} <small>{{ user.username }}</small></h3>
+{% endif %}
+
+{{ items.display(uncategorized_items, 0, allow_edit, _c) }}
+
+{% for category in portfolio %}
+    <div class="panel panel-info">
+        <div class="panel-body">
+            <h4 class="page-header">
+                <a href="#collapse-category-{{ category.id }}" role="button" data-toggle="collapse"
+                   aria-expanded="false" aria-controls="collapse-category-{{ category.id }}">
+                    {{ category.title }}
+                </a>
+
+                {% if allow_edit %}
+                    <div class="pull-right">
+                        <a href="{{ baseurl ~ {'action':'edit_category', 'id':category.id}|url_encode }}">
+                            {{ edit_img }}
+                        </a>
+                        {% if category.isVisible %}
+                            <a href="{{ baseurl ~ {'action':'hide_category', 'id':category.id}|url_encode }}">
+                                {{ visible_img }}
+                            </a>
+                        {% else %}
+                            <a href="{{ baseurl ~ {'action':'show_category', 'id':category.id}|url_encode }}">
+                                {{ invisible_img }}
+                            </a>
+                        {% endif %}
+                        <a href="{{ baseurl ~ {'action':'delete_category', 'id':category.id}|url_encode }}"
+                           class="btn-delete">
+                            {{ delete_img }}
+                        </a>
+                    </div>
+                {% endif %}
+            </h4>
+
+            <div>
+                {{ category.description }}
+            </div>
+
+            <div class="collapse" id="collapse-category-{{ category.id }}">
+                {{ items.display(category.items(course, session, not allow_edit), category.id, allow_edit, _c) }}
+            </div>
+        </div>
+    </div>
+{% endfor %}
+
+<script>
+    $(document).on('ready', function () {
+        $('.btn-delete').on('click', function (e) {
+            if (!confirm('{{ 'NoteConfirmDelete'|get_lang }} ')) {
+                e.preventDefault();
+            }
+        });
+    });
+</script>

+ 336 - 0
src/Chamilo/CoreBundle/Entity/Portfolio.php

@@ -0,0 +1,336 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Entity;
+
+use Chamilo\UserBundle\Entity\User;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * Class Portfolio.
+ *
+ * @package Chamilo\CoreBundle\Entity
+ *
+ * @ORM\Table(
+ *  name="portfolio",
+ *  indexes={
+ *   @ORM\Index(name="user", columns={"user_id"}),
+ *   @ORM\Index(name="course", columns={"c_id"}),
+ *   @ORM\Index(name="session", columns={"session_id"}),
+ *   @ORM\Index(name="category", columns={"category_id"})
+ *  }
+ * )
+ * Add @ to the next line if api_get_configuration_value('allow_portfolio_tool') is true
+ * ORM\Entity()
+ */
+class Portfolio
+{
+    /**
+     * @var int
+     *
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @var string
+     *
+     * @ORM\Column(name="title", type="string", length=255)
+     */
+    private $title;
+
+    /**
+     * @var string
+     * @ORM\Column(name="content", type="text")
+     */
+    private $content;
+
+    /**
+     * @var User
+     *
+     * @ORM\ManyToOne(targetEntity="Chamilo\UserBundle\Entity\User")
+     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
+     */
+    private $user;
+
+    /**
+     * @var Course
+     *
+     * @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course")
+     * @ORM\JoinColumn(name="c_id", referencedColumnName="id")
+     */
+    private $course = null;
+
+    /**
+     * @var Session
+     *
+     * @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Session")
+     * @ORM\JoinColumn(name="session_id", referencedColumnName="id")
+     */
+    private $session = null;
+
+    /**
+     * @var \DateTime
+     *
+     * @ORM\Column(name="creation_date", type="datetime")
+     */
+    private $creationDate;
+
+    /**
+     * @var \DateTime
+     *
+     * @ORM\Column(name="update_date", type="datetime")
+     */
+    private $updateDate;
+
+    /**
+     * @var bool
+     *
+     * @ORM\Column(name="is_visible", type="boolean", options={"default": true})
+     */
+    private $isVisible = true;
+
+    /**
+     * @var \Chamilo\CoreBundle\Entity\PortfolioCategory
+     *
+     * @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\PortfolioCategory", inversedBy="items")
+     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
+     */
+    private $category;
+
+    /**
+     * Portfolio constructor.
+     */
+    public function __construct()
+    {
+        $this->category = new PortfolioCategory();
+    }
+
+    /**
+     * Set user.
+     *
+     * @param User $user
+     *
+     * @return Portfolio
+     */
+    public function setUser(User $user)
+    {
+        $this->user = $user;
+
+        return $this;
+    }
+
+    /**
+     * Get user.
+     *
+     * @return User
+     */
+    public function getUser()
+    {
+        return $this->user;
+    }
+
+    /**
+     * Set course.
+     *
+     * @param Course|null $course
+     *
+     * @return Portfolio
+     */
+    public function setCourse(Course $course = null)
+    {
+        $this->course = $course;
+
+        return $this;
+    }
+
+    /**
+     * Get course.
+     *
+     * @return Course
+     */
+    public function getCourse()
+    {
+        return $this->course;
+    }
+
+    /**
+     * Get session.
+     *
+     * @return Session
+     */
+    public function getSession()
+    {
+        return $this->session;
+    }
+
+    /**
+     * Set session.
+     *
+     * @param Session|null $session
+     *
+     * @return Portfolio
+     */
+    public function setSession(Session $session = null)
+    {
+        $this->session = $session;
+
+        return $this;
+    }
+
+    /**
+     * Set title.
+     *
+     * @param string $title
+     *
+     * @return Portfolio
+     */
+    public function setTitle($title)
+    {
+        $this->title = $title;
+
+        return $this;
+    }
+
+    /**
+     * Get title.
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * Set content.
+     *
+     * @param string $content
+     *
+     * @return Portfolio
+     */
+    public function setContent($content)
+    {
+        $this->content = $content;
+
+        return $this;
+    }
+
+    /**
+     * Get content.
+     *
+     * @return string
+     */
+    public function getContent()
+    {
+        return $this->content;
+    }
+
+    /**
+     * Set creationDate.
+     *
+     * @param \DateTime $creationDate
+     *
+     * @return Portfolio
+     */
+    public function setCreationDate(\DateTime $creationDate)
+    {
+        $this->creationDate = $creationDate;
+
+        return $this;
+    }
+
+    /**
+     * Get creationDate.
+     *
+     * @return \DateTime
+     */
+    public function getCreationDate()
+    {
+        return $this->creationDate;
+    }
+
+    /**
+     * Set updateDate.
+     *
+     * @param \DateTime $updateDate
+     *
+     * @return Portfolio
+     */
+    public function setUpdateDate(\DateTime $updateDate)
+    {
+        $this->updateDate = $updateDate;
+
+        return $this;
+    }
+
+    /**
+     * Get updateDate.
+     *
+     * @return \DateTime
+     */
+    public function getUpdateDate()
+    {
+        return $this->updateDate;
+    }
+
+    /**
+     * Get id.
+     *
+     * @return int
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * Set isVisible.
+     *
+     * @param bool $isVisible
+     *
+     * @return Portfolio
+     */
+    public function setIsVisible($isVisible)
+    {
+        $this->isVisible = $isVisible;
+
+        return $this;
+    }
+
+    /**
+     * Get isVisible.
+     *
+     * @return bool
+     */
+    public function isVisible()
+    {
+        return $this->isVisible;
+    }
+
+    /**
+     * Get category.
+     *
+     * @return PortfolioCategory
+     */
+    public function getCategory()
+    {
+        return $this->category;
+    }
+
+    /**
+     * Set category.
+     *
+     * @param PortfolioCategory|null $category
+     *
+     * @return Portfolio
+     */
+    public function setCategory(PortfolioCategory $category = null)
+    {
+        $this->category = $category;
+
+        return $this;
+    }
+}

+ 251 - 0
src/Chamilo/CoreBundle/Entity/PortfolioCategory.php

@@ -0,0 +1,251 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Entity;
+
+use Chamilo\UserBundle\Entity\User;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Criteria;
+use Doctrine\ORM\Mapping as ORM;
+
+/**
+ * Class PortfolioCategory.
+ *
+ * @package Chamilo\CoreBundle\Entity
+ *
+ * @ORM\Table(
+ *  name="portfolio_category",
+ *  indexes={
+ *      @ORM\Index(name="user", columns={"user_id"})
+ *  }
+ * )
+ * Add @ to the next line if api_get_configuration_value('allow_portfolio_tool') is true
+ * ORM\Entity()
+ */
+class PortfolioCategory
+{
+    /**
+     * @var int
+     *
+     * @ORM\Column(name="id", type="integer")
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     */
+    private $id;
+
+    /**
+     * @var string
+     *
+     * @ORM\Column(name="title", type="string", length=255)
+     */
+    private $title;
+
+    /**
+     * @var null
+     *
+     * @ORM\Column(name="description", type="text", nullable=true)
+     */
+    private $description = null;
+
+    /**
+     * @var User
+     *
+     * @ORM\ManyToOne(targetEntity="Chamilo\UserBundle\Entity\User")
+     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
+     */
+    private $user;
+
+    /**
+     * @var bool
+     *
+     * @ORM\Column(name="is_visible", type="boolean", options={"default": true})
+     */
+    private $isVisible = true;
+
+    /**
+     * @var \Doctrine\Common\Collections\ArrayCollection
+     *
+     * @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\Portfolio", mappedBy="category")
+     */
+    private $items;
+
+    /**
+     * PortfolioCategory constructor.
+     */
+    public function __construct()
+    {
+        $this->items = new ArrayCollection();
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->title;
+    }
+
+    /**
+     * Get id.
+     *
+     * @return int
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param int $id
+     *
+     * @return PortfolioCategory
+     */
+    public function setId($id)
+    {
+        $this->id = $id;
+
+        return $this;
+    }
+
+    /**
+     * Get title.
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * Set title.
+     *
+     * @param string $title
+     *
+     * @return PortfolioCategory
+     */
+    public function setTitle($title)
+    {
+        $this->title = $title;
+
+        return $this;
+    }
+
+    /**
+     * Get description.
+     *
+     * @return string|null
+     */
+    public function getDescription()
+    {
+        return $this->description;
+    }
+
+    /**
+     * Set description.
+     *
+     * @param string|null $description
+     *
+     * @return PortfolioCategory
+     */
+    public function setDescription($description)
+    {
+        $this->description = $description;
+
+        return $this;
+    }
+
+    /**
+     * Get user.
+     *
+     * @return User
+     */
+    public function getUser()
+    {
+        return $this->user;
+    }
+
+    /**
+     * Set user.
+     *
+     * @param User $user
+     *
+     * @return PortfolioCategory
+     */
+    public function setUser(User $user)
+    {
+        $this->user = $user;
+
+        return $this;
+    }
+
+    /**
+     * Get isVisible.
+     *
+     * @return bool
+     */
+    public function isVisible()
+    {
+        return $this->isVisible;
+    }
+
+    /**
+     * Set isVisible.
+     *
+     * @param bool $isVisible
+     *
+     * @return PortfolioCategory
+     */
+    public function setIsVisible($isVisible)
+    {
+        $this->isVisible = $isVisible;
+
+        return $this;
+    }
+
+    /**
+     * Get items.
+     *
+     * @param Course|null  $course
+     * @param Session|null $session
+     * @param bool         $onlyVisibles
+     *
+     * @return ArrayCollection
+     */
+    public function getItems(Course $course = null, Session $session = null, $onlyVisibles = false)
+    {
+        $criteria = Criteria::create();
+
+        if ($onlyVisibles) {
+            $criteria->andWhere(
+                Criteria::expr()->eq('isVisible', true)
+            );
+        }
+
+        if ($course) {
+            $criteria
+                ->andWhere(
+                    Criteria::expr()->eq('course', $course)
+                )
+                ->andWhere(
+                    Criteria::expr()->eq('session', $session)
+                );
+        }
+
+        return $this->items->matching($criteria);
+    }
+
+    /**
+     * Set items.
+     *
+     * @param ArrayCollection $items
+     *
+     * @return PortfolioCategory
+     */
+    public function setItems(ArrayCollection $items)
+    {
+        $this->items = $items;
+
+        return $this;
+    }
+}