Explorar el Código

Adding trayectoria see BT#6397

Julio Montoya hace 11 años
padre
commit
7a7cb5ea9d
Se han modificado 30 ficheros con 1106 adiciones y 8 borrados
  1. 31 0
      main/inc/Entity/CurriculumItem.php
  2. 40 0
      main/inc/Entity/CurriculumItemRelUser.php
  3. 12 0
      main/inc/Entity/User.php
  4. 4 1
      main/inc/routes.php
  5. 22 2
      main/inc/services.php
  6. 2 2
      main/template/default/admin/administrator/index.tpl
  7. 5 0
      main/template/default/tool/curriculum/category/add.tpl
  8. 10 0
      main/template/default/tool/curriculum/category/add_from_parent.tpl
  9. 5 0
      main/template/default/tool/curriculum/category/edit.tpl
  10. 7 0
      main/template/default/tool/curriculum/category/list.tpl
  11. 13 0
      main/template/default/tool/curriculum/category/read.tpl
  12. 5 0
      main/template/default/tool/curriculum/item/add.tpl
  13. 10 0
      main/template/default/tool/curriculum/item/add_from_category.tpl
  14. 5 0
      main/template/default/tool/curriculum/item/edit.tpl
  15. 21 0
      main/template/default/tool/curriculum/item/list.tpl
  16. 13 0
      main/template/default/tool/curriculum/item/read.tpl
  17. 5 0
      main/template/default/tool/curriculum/user/add.tpl
  18. 10 0
      main/template/default/tool/curriculum/user/add_from_category.tpl
  19. 5 0
      main/template/default/tool/curriculum/user/edit.tpl
  20. 105 0
      main/template/default/tool/curriculum/user/list.tpl
  21. 13 0
      main/template/default/tool/curriculum/user/read.tpl
  22. 1 1
      src/ChamiloLMS/Controller/Admin/Administrator/BranchController.php
  23. 207 0
      src/ChamiloLMS/Controller/Tool/Curriculum/CurriculumCategoryController.php
  24. 157 0
      src/ChamiloLMS/Controller/Tool/Curriculum/CurriculumItemController.php
  25. 200 0
      src/ChamiloLMS/Controller/Tool/Curriculum/CurriculumUserController.php
  26. 2 2
      src/ChamiloLMS/Form/BranchType.php
  27. 50 0
      src/ChamiloLMS/Form/CurriculumCategoryType.php
  28. 54 0
      src/ChamiloLMS/Form/CurriculumItemRelUserCollectionType.php
  29. 43 0
      src/ChamiloLMS/Form/CurriculumItemRelUserType.php
  30. 49 0
      src/ChamiloLMS/Form/CurriculumItemType.php

+ 31 - 0
main/inc/Entity/CurriculumItem.php

@@ -3,6 +3,7 @@
 namespace Entity;
 
 use Doctrine\ORM\Mapping as ORM;
+use Doctrine\Common\Collections\ArrayCollection;
 
 /**
  * CurriculumItem
@@ -55,6 +56,16 @@ class CurriculumItem
      */
     private $category;
 
+    /**
+     * @ORM\OneToMany(targetEntity="CurriculumItemRelUser", mappedBy="item")
+     */
+    private $userItems;
+
+    public function __construct()
+    {
+        $this->userItems = new ArrayCollection();
+    }
+
     /**
      *
      * @return CurriculumCategory
@@ -64,6 +75,26 @@ class CurriculumItem
         return $this->category;
     }
 
+    /**
+     *
+     * @return CurriculumCategory
+     */
+    public function getUserItems()
+    {
+        return $this->userItems;
+    }
+
+
+    /**
+     *
+     * @return CurriculumCategory
+     */
+    public function setUserItems($userItem)
+    {
+        $this->userItems = $userItem;
+    }
+
+
     /**
      * @param CurriculumCategory $category
      */

+ 40 - 0
main/inc/Entity/CurriculumItemRelUser.php

@@ -49,6 +49,46 @@ class CurriculumItemRelUser
      */
     private $description;
 
+    /**
+     * @ORM\OneToMany(targetEntity="User", mappedBy="curriculumItems")
+     */
+    //private $user;
+
+    /**
+     * @ORM\ManyToOne(targetEntity="User"))
+     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id", nullable=true)
+     */
+    private $user;
+
+     /**
+     * @ORM\ManyToOne(targetEntity="CurriculumItem")
+     * @ORM\JoinColumn(name="item_id", referencedColumnName="id", nullable=true)
+     */
+    private $item;
+
+
+    public function getUser()
+    {
+        return $this->user;
+    }
+
+    public function getItem()
+    {
+        return $this->item;
+    }
+
+    /**
+     * @param CurriculumItem $item
+     */
+    public function setItem(CurriculumItem $item)
+    {
+        $this->item = $item;
+    }
+
+    public function setUser(User $user)
+    {
+        $this->user = $user;
+    }
 
     /**
      * Get id

+ 12 - 0
main/inc/Entity/User.php

@@ -239,6 +239,17 @@ class User implements AdvancedUserInterface, \Serializable
 
     private $isActive;
 
+    /**
+     * @ORM\ManyToOne(targetEntity="CurriculumItemRelUser")
+     * @ORM\JoinColumn(name="user_id", referencedColumnName="user_id", nullable=true)
+     */
+    private $curriculumItems;
+
+    public function getCurriculumItems()
+    {
+        return $this->curriculumItems;
+    }
+
     /**
      *
      */
@@ -248,6 +259,7 @@ class User implements AdvancedUserInterface, \Serializable
         $this->items = new ArrayCollection();
         $this->classes = new ArrayCollection();
         $this->roles = new ArrayCollection();
+        $this->curriculumItems = new ArrayCollection();
         $this->salt = sha1(uniqid(null, true));
         $this->isActive = true;
     }

+ 4 - 1
main/inc/routes.php

@@ -674,7 +674,6 @@ if ($alreadyInstalled) {
     $app->mount('/admin/administrator/question_scores', new ChamiloLMS\Provider\ReflectionControllerProvider('question_score.controller'));
     $app->mount('/admin/administrator/question_score_names', new ChamiloLMS\Provider\ReflectionControllerProvider('question_score_name.controller'));
 
-
     // Ministerio routes:
 
     $app->mount('/admin/administrator/branches', new ChamiloLMS\Provider\ReflectionControllerProvider('branch.controller'));
@@ -684,6 +683,10 @@ if ($alreadyInstalled) {
     $app->mount('/admin/jury_president', new ChamiloLMS\Provider\ReflectionControllerProvider('jury_president.controller'));
     $app->mount('/admin/jury_member', new ChamiloLMS\Provider\ReflectionControllerProvider('jury_member.controller'));
 
+    $app->mount('/tool/curriculum/category', new ChamiloLMS\Provider\ReflectionControllerProvider('curriculum_category.controller'));
+    $app->mount('/tool/curriculum/item', new ChamiloLMS\Provider\ReflectionControllerProvider('curriculum_item.controller'));
+    $app->mount('/tool/curriculum/user', new ChamiloLMS\Provider\ReflectionControllerProvider('curriculum_user.controller'));
+
 }
 
 

+ 22 - 2
main/inc/services.php

@@ -110,11 +110,12 @@ $app['security.role_hierarchy'] = array(
 // Role rules
 $app['security.access_rules'] = array(
     //array('^/admin', 'ROLE_ADMIN', 'https'),
-    array('^/admin/administrator', array('ROLE_ADMIN')),
+    array('^/admin/administrator', 'ROLE_ADMIN'),
     array('^/main/admin/.*', 'ROLE_ADMIN'),
     array('^/admin/questionmanager', 'ROLE_QUESTION_MANAGER'),
     array('^/main/.*', array('ROLE_STUDENT')),
     array('^/admin/director', 'ROLE_DIRECTOR'),
+    array('^/tool/.*', array('ROLE_ADMIN','ROLE_TEACHER')),
     array('^/admin/jury_president', 'ROLE_JURY_PRESIDENT'),
     array('^/admin/jury_member', 'ROLE_JURY_MEMBER') //? jury subsitute??
     //array('^.*$', 'ROLE_USER'),
@@ -633,7 +634,6 @@ $app['branch_director.controller'] = $app->share(
     }
 );
 
-
 $app['jury.controller'] = $app->share(
     function () use ($app) {
         return new ChamiloLMS\Controller\Admin\Administrator\JuryController($app);
@@ -652,4 +652,24 @@ $app['jury_member.controller'] = $app->share(
     }
 );
 
+$app['curriculum_category.controller'] = $app->share(
+    function () use ($app) {
+        return new ChamiloLMS\Controller\Tool\Curriculum\CurriculumCategoryController($app);
+    }
+);
+
+$app['curriculum_item.controller'] = $app->share(
+    function () use ($app) {
+        return new ChamiloLMS\Controller\Tool\Curriculum\CurriculumItemController($app);
+    }
+);
+
+$app['curriculum_user.controller'] = $app->share(
+    function () use ($app) {
+        return new ChamiloLMS\Controller\Tool\Curriculum\CurriculumUserController($app);
+    }
+);
+
+
+
 

+ 2 - 2
main/template/default/admin/administrator/index.tpl

@@ -3,10 +3,10 @@
 {% block content %}
 <ul>
     <li>
-        <a href="{{ url('question_score_name.controller:indexAction') }}">{{ 'Question names' |trans }}</a>
+        <a href="{{ url('question_score.controller:indexAction') }}">{{ 'Question score name' |trans }}</a>
     </li>
     <li>
-        <a href="{{ url('question_score.controller:indexAction') }}">{{ 'Question score name' |trans }}</a>
+        <a href="{{ url('question_score_name.controller:indexAction') }}">{{ 'Question names' |trans }}</a>
     </li>
     <li>
         <a href="{{ url('role.controller:indexAction') }}">{{ 'Roles' |trans }}</a>

+ 5 - 0
main/template/default/tool/curriculum/category/add.tpl

@@ -0,0 +1,5 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {% import app.template_style ~ "/default_actions/settings.tpl" as actions %}
+    {{ actions.add(form, links) }}
+{% endblock %}

+ 10 - 0
main/template/default/tool/curriculum/category/add_from_parent.tpl

@@ -0,0 +1,10 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    <a href="{{ url(links.list_link) }}">
+        List
+    </a>
+    <hr />
+    <form action="{{ url(links.add_from_parent_link, { "id" : parent_id }) }}" method="post" {{ form_enctype(form) }}>
+        {{ form_widget(form) }}
+    </form>
+{% endblock %}

+ 5 - 0
main/template/default/tool/curriculum/category/edit.tpl

@@ -0,0 +1,5 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {% import app.template_style ~ "/default_actions/settings.tpl" as actions %}
+    {{ actions.edit(form, links) }}
+{% endblock %}

+ 7 - 0
main/template/default/tool/curriculum/category/list.tpl

@@ -0,0 +1,7 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    <a href="{{ url(links.create_link) }}">
+        Add
+    </a>
+    {{ tree }}
+{% endblock %}

+ 13 - 0
main/template/default/tool/curriculum/category/read.tpl

@@ -0,0 +1,13 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {{ item.id }} {{ item.name  }}
+    <hr />
+    <ul>
+    {% for subitem in subitems %}
+        <li>
+            <a href="{{ url(links.question_score_name_read_link, { id: subitem.id} ) }}">{{ subitem.name }}</a>
+        </li>
+    {% endfor %}
+    </ul>
+
+{% endblock %}

+ 5 - 0
main/template/default/tool/curriculum/item/add.tpl

@@ -0,0 +1,5 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {% import app.template_style ~ "/default_actions/settings.tpl" as actions %}
+    {{ actions.add(form, links) }}
+{% endblock %}

+ 10 - 0
main/template/default/tool/curriculum/item/add_from_category.tpl

@@ -0,0 +1,10 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    <a href="{{ url(links.list_link) }}">
+        List
+    </a>
+    <hr />
+    <form action="{{ url(links.add_from_category, { "id" : parent_id }) }}" method="post" {{ form_enctype(form) }}>
+        {{ form_widget(form) }}
+    </form>
+{% endblock %}

+ 5 - 0
main/template/default/tool/curriculum/item/edit.tpl

@@ -0,0 +1,5 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {% import app.template_style ~ "/default_actions/settings.tpl" as actions %}
+    {{ actions.edit(form, links) }}
+{% endblock %}

+ 21 - 0
main/template/default/tool/curriculum/item/list.tpl

@@ -0,0 +1,21 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    <a href="{{ url(links.create_link) }}">
+        {{ 'Add' |trans }}
+    </a>
+    <table class="table">
+    {% for item in items %}
+        <tr>
+            <td>
+                <a href="{{ url(links.read_link, { id: item.id }) }}">
+                {{ item.title }}
+                </a>
+            </td>
+            <td>
+                <a class="btn" href="{{ url(links.update_link, { id: item.id }) }}"> {{ 'Edit' |trans }}</a>
+                <a class="btn" href="{{ url(links.delete_link, { id: item.id }) }}"> {{ 'Delete' |trans }}</a>
+            </td>
+        </tr>
+    {% endfor %}
+    </table>
+{% endblock %}

+ 13 - 0
main/template/default/tool/curriculum/item/read.tpl

@@ -0,0 +1,13 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {{ item.id }} {{ item.name  }}
+    <hr />
+    <ul>
+    {% for subitem in subitems %}
+        <li>
+            <a href="{{ url(links.question_score_name_read_link, { id: subitem.id} ) }}">{{ subitem.name }}</a>
+        </li>
+    {% endfor %}
+    </ul>
+
+{% endblock %}

+ 5 - 0
main/template/default/tool/curriculum/user/add.tpl

@@ -0,0 +1,5 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {% import app.template_style ~ "/default_actions/settings.tpl" as actions %}
+    {{ actions.add(form, links) }}
+{% endblock %}

+ 10 - 0
main/template/default/tool/curriculum/user/add_from_category.tpl

@@ -0,0 +1,10 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    <a href="{{ url(links.list_link) }}">
+        List
+    </a>
+    <hr />
+    <form action="{{ url(links.add_from_category, { "id" : parent_id }) }}" method="post" {{ form_enctype(form) }}>
+        {{ form_widget(form) }}
+    </form>
+{% endblock %}

+ 5 - 0
main/template/default/tool/curriculum/user/edit.tpl

@@ -0,0 +1,5 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {% import app.template_style ~ "/default_actions/settings.tpl" as actions %}
+    {{ actions.edit(form, links) }}
+{% endblock %}

+ 105 - 0
main/template/default/tool/curriculum/user/list.tpl

@@ -0,0 +1,105 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+
+{% macro widget_prototype(widget, remove_text) %}
+
+
+    {% if widget.get('prototype') %}
+        {% set form = widget.get('prototype') %}
+        {% set name = widget.get('prototype').get('description') %}
+    {% else %}
+        {% set form = widget %}
+        {% set name = widget.get('full_name') %}
+    {% endif %}
+
+    <div data-content="{{ name }}">
+        <a class="btn-remove" data-related="{{ name }}">{{ remove_text }}</a>
+        {{ form_widget(form) }}
+    </div>
+
+{% endmacro %}
+
+{% block content %}
+
+<script>
+$(function() {
+
+    $('.btn-add[data-target]').live('click', function(event) {
+        var collectionHolder = $('#' + $(this).attr('data-target'));
+
+
+        if (!collectionHolder.attr('data-counter')) {
+            collectionHolder.attr('data-counter', collectionHolder.children().length);
+        }
+
+        var prototype = collectionHolder.attr('data-prototype');
+
+        var form = prototype.replace(/__name__/g, collectionHolder.attr('data-counter'));
+
+        collectionHolder.attr('data-counter', Number(collectionHolder.attr('data-counter')) + 1);
+        //collectionHolder.append(form);
+        var removeFormA = $('<a class="btn btn-danger" href="#">{{ 'Delete' | get_lang }}</a>');
+        var liItem = $('<li id="'+collectionHolder.attr('data-counter')+'">'+form+'</li>').append(removeFormA);
+        var item = collectionHolder.find('ul').append(liItem);
+        addTagFormDeleteLink(removeFormA);
+        event && event.preventDefault();
+    });
+});
+
+
+function addTagFormDeleteLink($tagFormLi) {
+    $tagFormLi.on('click', function(e) {
+        e.preventDefault();
+        $(this).parent().remove();
+    });
+}
+
+function save(itemId) {
+    var form = $("#"+itemId).parent();
+    var serializedForm = form.serialize();
+    $.post('{{ url('curriculum_user.controller:saveUserItemAction') }}', serializedForm );
+    return false;
+}
+
+</script>
+    <h2>Trayectoria</h2>
+
+    <p>Explicaciones</p>
+    <p>Las respuestas a este formulario son de carácter jurado.</p>
+
+    {% for subcategory in categories %}
+        <h3> {{ subcategory.title }}</h3>
+        {% for item in subcategory.items %}
+            <h4> {{ item.title }} (item)</h4>
+
+            {{ form_start(form_list[item.id]) }}
+                <div id="items_{{ item.id }}" class="items" data-prototype="{{ form_widget(form_list[item.id].userItems.vars.prototype)|e }}" >
+                    <ul>
+
+                    {% if item.userItems|length == 0 %}
+                    {% else %}
+                        {% for userItem in item.userItems %}
+
+                        {% endfor %}
+                    {% endif %}
+
+                    </ul>
+                    {% for widget in form_list[item.id].items.children %}
+                        {{ widget }}
+                        {{ _self.widget_prototype(widget, 'Remove item') }}
+                    {% endfor %}
+
+                    <div class="btn-group">
+                        {# form_widget(form_list[item.id].submit) #}
+                        <a class="btn btn-success" onclick="save('items_{{ item.id }}');" data-target="items_{{ item.id }}">{{ 'Save item' | get_lang }}</a>
+                        <a class="btn-add btn btn-primary" data-target="items_{{ item.id }}">{{ 'Add' | get_lang }}</a>
+                    </div>
+                </div>
+            {{ form_end(form_list[item.id]) }}
+
+        {% endfor %}
+    {% endfor %}
+
+
+
+
+{% endblock %}

+ 13 - 0
main/template/default/tool/curriculum/user/read.tpl

@@ -0,0 +1,13 @@
+{% extends app.template_style ~ "/layout/layout_1_col.tpl" %}
+{% block content %}
+    {{ item.id }} {{ item.name  }}
+    <hr />
+    <ul>
+    {% for subitem in subitems %}
+        <li>
+            <a href="{{ url(links.question_score_name_read_link, { id: subitem.id} ) }}">{{ subitem.name }}</a>
+        </li>
+    {% endfor %}
+    </ul>
+
+{% endblock %}

+ 1 - 1
src/ChamiloLMS/Controller/Admin/Administrator/BranchController.php

@@ -126,8 +126,8 @@ class BranchController extends CommonController
         $template->assign('form', $form->createView());
         $template->assign('parent_id', $id);
         $response = $template->render_template($this->getTemplatePath().'add_from_parent.tpl');
-        return new Response($response, 200, array());
 
+        return new Response($response, 200, array());
     }
 
     /**

+ 207 - 0
src/ChamiloLMS/Controller/Tool/Curriculum/CurriculumCategoryController.php

@@ -0,0 +1,207 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace ChamiloLMS\Controller\Tool\Curriculum;
+
+use ChamiloLMS\Controller\CommonController;
+use Silex\Application;
+use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
+use Symfony\Component\HttpFoundation\Response;
+use Entity;
+use ChamiloLMS\Form\CurriculumCategoryType;
+use Symfony\Component\Routing\Annotation\Route;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
+
+/**
+ * Class CurriculumController
+ * @todo @route and @method function don't work yet
+ * @package ChamiloLMS\Controller
+ * @author Julio Montoya <gugli100@gmail.com>
+ */
+class CurriculumCategoryController extends CommonController
+{
+    /**
+     *
+     * @Route("/")
+     * @Method({"GET"})
+     */
+    public function indexAction()
+    {
+        //return parent::listingAction();
+
+        $options = array(
+            'decorate' => true,
+            'rootOpen' => '<ul>',
+            'rootClose' => '</ul>',
+            'childOpen' => '<li>',
+            'childClose' => '</li>',
+            'nodeDecorator' => function($row) {
+                $addChildren = null;
+                $items = null;
+                if ($row['lvl'] <= 0) {
+                    $addChildren = '<a class="btn" href="'.$this->createUrl('add_from_parent_link', array('id' => $row['id'])).'">Add children</a>';
+                } else {
+                    $addChildren = '<a class="btn" href="'.$this->createUrl('add_from_category', array('id' => $row['id'])).'">Add items</a>';
+                    //$items = $row['items'];
+                    $items = '<ul>';
+                    foreach ($row['items'] as $item) {
+                        $url = ' <a class="btn" href="'.$this->createUrl('edit_item', array('id' => $item['id'])).'">Edit</a>';
+                        $items.= '<li>'.$item['title']." (item) ".$url.'</li>';
+                    }
+                    $items .= '</ul>';
+                }
+                $readLink = '<a href="'.$this->createUrl('read_link', array('id' => $row['id'])).'">'.$row['title'].'</a>';
+                $editLink = '<a class="btn" href="'.$this->createUrl('update_link', array('id' => $row['id'])).'">Edit</a>';
+                $deleteLink = '<a class="btn" href="'.$this->createUrl('delete_link', array('id' => $row['id'])).'"/>Delete</a>';
+
+                return $readLink.' '.$addChildren.' '.$editLink.' '.$deleteLink.$items;
+            }
+            //'representationField' => 'slug',
+            //'html' => true
+        );
+
+        // @todo put this in a function
+        $repo = $this->getRepository();
+
+        $query = $this->getManager()
+            ->createQueryBuilder()
+            ->select('node, i')
+            ->from('Entity\CurriculumCategory', 'node')
+            ->leftJoin('node.items', 'i')
+            //->where('node.cId = 0')
+            ->orderBy('node.root, node.lft', 'ASC')
+            ->getQuery();
+
+        $htmlTree = $repo->buildTree($query->getArrayResult(), $options);
+        $this->get('template')->assign('tree', $htmlTree);
+        $this->get('template')->assign('links', $this->generateLinks());
+        $response = $this->get('template')->render_template($this->getTemplatePath().'list.tpl');
+        return new Response($response, 200, array());
+
+    }
+
+    /**
+    *
+    * @Route("/{id}", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function readAction($id)
+    {
+        return parent::readAction($id);
+    }
+
+    /**
+    * @Route("/add")
+    * @Method({"GET"})
+    */
+    public function addAction()
+    {
+        return parent::addAction();
+    }
+
+    /**
+    * @Route("/{id}/add")
+    * @Method({"GET, POST"})
+    */
+    public function addFromParentAction($id)
+    {
+        $request = $this->getRequest();
+        $formType = $this->getFormType();
+
+        $entity = new Entity\CurriculumCategory();
+        $parentEntity = $this->getEntity($id);
+        $entity->setParent($parentEntity);
+        $form = $this->get('form.factory')->create($formType, $entity);
+
+        if ($request->getMethod() == 'POST') {
+            $form->bind($request);
+            if ($form->isValid()) {
+                /** @var Entity\CurriculumCategory $item */
+                $item = $form->getData();
+                $em = $this->getManager();
+                $em->persist($item);
+                $em->flush();
+
+                $this->get('session')->getFlashBag()->add('success', "Added");
+                $url = $this->createUrl('list_link');
+                return $this->redirect($url);
+            }
+        }
+
+        $template = $this->get('template');
+        $template->assign('links', $this->generateLinks());
+        $template->assign('form', $form->createView());
+        $template->assign('parent_id', $id);
+        $response = $template->render_template($this->getTemplatePath().'add_from_parent.tpl');
+
+        return new Response($response, 200, array());
+    }
+
+    /**
+    *
+    * @Route("/{id}/edit", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function editAction($id)
+    {
+        return parent::editAction($id);
+    }
+
+    /**
+    *
+    * @Route("/{id}/delete", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function deleteAction($id)
+    {
+        return parent::deleteAction($id);
+    }
+
+    protected function getControllerAlias()
+    {
+        return 'curriculum_category.controller';
+    }
+
+    protected function generateDefaultCrudRoutes()
+    {
+        $routes = parent::generateDefaultCrudRoutes();
+        $routes['add_from_parent_link'] = 'curriculum_category.controller:addFromParentAction';
+        $routes['add_from_category'] = 'curriculum_item.controller:addFromCategoryAction';
+        $routes['edit_item'] = 'curriculum_item.controller:editAction';
+
+
+        return $routes ;
+    }
+
+    /**
+    * {@inheritdoc}
+    */
+    protected function getTemplatePath()
+    {
+        return 'tool/curriculum/category/';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getRepository()
+    {
+        return $this->get('orm.em')->getRepository('Entity\CurriculumCategory');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getNewEntity()
+    {
+        return new Entity\CurriculumCategory();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getFormType()
+    {
+        return new CurriculumCategoryType();
+    }
+}

+ 157 - 0
src/ChamiloLMS/Controller/Tool/Curriculum/CurriculumItemController.php

@@ -0,0 +1,157 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace ChamiloLMS\Controller\Tool\Curriculum;
+
+use ChamiloLMS\Controller\CommonController;
+use Silex\Application;
+use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
+use Symfony\Component\HttpFoundation\Response;
+use Entity;
+use ChamiloLMS\Form\CurriculumItemType;
+use Symfony\Component\Routing\Annotation\Route;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
+
+/**
+ * Class CurriculumItemController
+ * @todo @route and @method function don't work yet
+ * @package ChamiloLMS\Controller
+ * @author Julio Montoya <gugli100@gmail.com>
+ */
+class CurriculumItemController extends CommonController
+{
+    /**
+     *
+     * @Route("/")
+     * @Method({"GET"})
+     */
+    public function indexAction()
+    {
+        return parent::listingAction();
+    }
+
+    /**
+    *
+    * @Route("/{id}", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function readAction($id)
+    {
+        return parent::readAction($id);
+    }
+
+    /**
+    * @Route("/add")
+    * @Method({"GET"})
+    */
+    public function addAction()
+    {
+        return parent::addAction();
+    }
+
+    /**
+    * @Route("/add-from-category/{id}")
+    * @Method({"GET, POST"})
+    */
+    public function addFromCategoryAction($id)
+    {
+        $request = $this->getRequest();
+        $formType = $this->getFormType();
+
+        $entity = new Entity\CurriculumItem();
+        //$category = new Entity\CurriculumCategory();
+        $category = $this->get('orm.em')->getRepository('Entity\CurriculumCategory')->find($id);
+        $entity->setCategory($category);
+
+        $form = $this->get('form.factory')->create($formType, $entity);
+
+        if ($request->getMethod() == 'POST') {
+            $form->bind($request);
+            if ($form->isValid()) {
+                /** @var Entity\CurriculumCategory $item */
+                $item = $form->getData();
+                $em = $this->getManager();
+                $em->persist($item);
+                $em->flush();
+
+                $this->get('session')->getFlashBag()->add('success', "Added");
+                $url = $this->createUrl('list_link');
+                return $this->redirect($url);
+            }
+        }
+
+        $template = $this->get('template');
+        $template->assign('links', $this->generateLinks());
+        $template->assign('form', $form->createView());
+        $template->assign('parent_id', $id);
+        $response = $template->render_template($this->getTemplatePath().'add_from_category.tpl');
+
+        return new Response($response, 200, array());
+    }
+
+    /**
+    *
+    * @Route("/{id}/edit", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function editAction($id)
+    {
+        return parent::editAction($id);
+    }
+
+    /**
+    *
+    * @Route("/{id}/delete", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function deleteAction($id)
+    {
+        return parent::deleteAction($id);
+    }
+
+    protected function getControllerAlias()
+    {
+        return 'curriculum_item.controller';
+    }
+
+    protected function generateDefaultCrudRoutes()
+    {
+        $routes = parent::generateDefaultCrudRoutes();
+        $routes['add_from_category'] = 'curriculum_item.controller:addFromCategoryAction';
+        //$routes['add_items'] = 'curriculum_item.controller:addItemsAction';
+
+        return $routes ;
+    }
+
+    /**
+    * {@inheritdoc}
+    */
+    protected function getTemplatePath()
+    {
+        return 'tool/curriculum/item/';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getRepository()
+    {
+        return $this->get('orm.em')->getRepository('Entity\CurriculumItem');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getNewEntity()
+    {
+        return new Entity\CurriculumItem();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getFormType()
+    {
+        return new CurriculumItemType();
+    }
+}

+ 200 - 0
src/ChamiloLMS/Controller/Tool/Curriculum/CurriculumUserController.php

@@ -0,0 +1,200 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace ChamiloLMS\Controller\Tool\Curriculum;
+
+use ChamiloLMS\Controller\CommonController;
+use Silex\Application;
+use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
+use Symfony\Component\HttpFoundation\Response;
+use Entity;
+use ChamiloLMS\Form\CurriculumItemRelUserCollectionType;
+use Symfony\Component\Routing\Annotation\Route;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
+
+/**
+ * Class CurriculumUserController
+ * @todo @route and @method function don't work yet
+ * @package ChamiloLMS\Controller
+ * @author Julio Montoya <gugli100@gmail.com>
+ */
+class CurriculumUserController extends CommonController
+{
+    /**
+     *
+     * @Route("/")
+     * @Method({"GET"})
+     */
+    public function indexAction()
+    {
+        // @todo put this in a function
+        $repo = $this->getCurriculumCategoryRepository();
+
+        $query = $this->getManager()
+            ->createQueryBuilder()
+            ->select('node, i')
+            ->from('Entity\CurriculumCategory', 'node')
+            ->innerJoin('node.items', 'i')
+            ->leftJoin('i.userItems', 'u')
+            ->orderBy('node.root, node.lft', 'ASC')
+            ->getQuery();
+
+        $categories = $query->getResult();
+
+        $formList = array();
+        /** @var \Entity\CurriculumCategory $category */
+
+        foreach ($categories as $category) {
+            /** @var \Entity\CurriculumItem $item */
+            foreach ($category->getItems() as $item) {
+                //$userItems = $item->getUserItems();
+                //var_dump(get_class($userItems));
+                $formType = new CurriculumItemRelUserCollectionType($item->getId());
+                $form = $this->get('form.factory')->create($formType, $item);
+                $formList[$item->getId()] = $form->createView();
+            }
+        }
+
+        $this->get('template')->assign('categories', $query->getResult());
+        $this->get('template')->assign('links', $this->generateLinks());
+        $this->get('template')->assign('form_list', $formList);
+
+        $response = $this->get('template')->render_template($this->getTemplatePath().'list.tpl');
+        return new Response($response, 200, array());
+    }
+
+    /**
+    *
+    * @Route("/save-user-item")
+    * @Method({"POST"})
+    */
+    public function saveUserItemAction()
+    {
+        $request = $this->getRequest();
+        $form = $this->get('form.factory')->create($this->getFormType());
+        $token = $this->get('security')->getToken();
+
+        if ($request->getMethod() == 'POST') {
+            $form->bind($request);
+
+            if ($form->isValid()) {
+                /** @var Entity\CurriculumItem $item */
+                $item = $form->getData();
+
+                $user = $token->getUser();
+                // @todo check this
+                $user = $this->get('orm.em')->getRepository('Entity\User')->find($user->getUserId());
+
+                $counter = 1;
+                /** @var Entity\CurriculumItemRelUser $curriculumItemRelUser  */
+                foreach ($item->getUserItems() as $curriculumItemRelUser) {
+                    $curriculumItemRelUser->setUser($user);
+                    //$item = new Entity\CurriculumItem();
+                    $item = $this->getCurriculumItemRepository()->find($curriculumItemRelUser->getItemId());
+                    $curriculumItemRelUser->setItem($item);
+                    $curriculumItemRelUser->setOrderId(strval($counter));
+                    $this->createAction($curriculumItemRelUser);
+                    $counter++;
+                }
+            }
+        }
+        $response = null;
+        return new Response($response, 200, array());
+    }
+
+    /**
+    *
+    * @Route("/{id}", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function readAction($id)
+    {
+        return parent::readAction($id);
+    }
+
+    /**
+    * @Route("/add")
+    * @Method({"GET"})
+    */
+    public function addAction()
+    {
+        return parent::addAction();
+    }
+
+    /**
+    *
+    * @Route("/{id}/edit", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function editAction($id)
+    {
+        return parent::editAction($id);
+    }
+
+    /**
+    *
+    * @Route("/{id}/delete", requirements={"id" = "\d+"}, defaults={"foo" = "bar"})
+    * @Method({"GET"})
+    */
+    public function deleteAction($id)
+    {
+        return parent::deleteAction($id);
+    }
+
+    protected function getControllerAlias()
+    {
+        return 'curriculum_user.controller';
+    }
+
+    protected function generateDefaultCrudRoutes()
+    {
+        $routes = parent::generateDefaultCrudRoutes();
+        $routes['add_from_category'] = 'curriculum_item.controller:addFromCategoryAction';
+        //$routes['add_items'] = 'curriculum_item.controller:addItemsAction';
+
+        return $routes ;
+    }
+
+    /**
+    * {@inheritdoc}
+    */
+    protected function getTemplatePath()
+    {
+        return 'tool/curriculum/user/';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getRepository()
+    {
+        return $this->get('orm.em')->getRepository('Entity\CurriculumItemRelUser');
+    }
+
+    private function getCurriculumCategoryRepository()
+    {
+        return $this->get('orm.em')->getRepository('Entity\CurriculumCategory');
+    }
+
+    private function getCurriculumItemRepository()
+    {
+        return $this->get('orm.em')->getRepository('Entity\CurriculumItem');
+    }
+
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getNewEntity()
+    {
+        return new Entity\CurriculumItemRelUser();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getFormType()
+    {
+        return new CurriculumItemRelUserCollectionType();
+    }
+}

+ 2 - 2
src/ChamiloLMS/Form/BranchType.php

@@ -43,8 +43,8 @@ class BranchType extends AbstractType
             ->add('admin_name', 'text')
             ->add('admin_phone', 'text', array('required' => false))
             ->add('last_sync_trans_date', 'datetime', array(
-                    'data' => new \DateTime()
-                    )
+                'data' => new \DateTime()
+                )
             )
             ->add('last_sync_type', 'text')
             ->add('last_sync_trans_id', 'text')

+ 50 - 0
src/ChamiloLMS/Form/CurriculumCategoryType.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace ChamiloLMS\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+use Entity;
+
+class CurriculumCategoryType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builderData = $builder->getData();
+        /*$parentIdDisabled = false;
+        if (!empty($builderData)) {
+            $parentIdDisabled = true;
+        }*/
+
+        $builder->add('title', 'text');
+        $builder->add('max_score', 'text');
+        $builder->add('min_chars', 'text');
+        $builder->add('min_chars', 'text');
+        $builder->add('parent', 'entity', array(
+            'class' => 'Entity\CurriculumCategory',
+            'query_builder' => function($repository) {
+                return $repository->createQueryBuilder('p')
+                    ->orderBy('p.title', 'ASC');
+            },
+            'property' => 'title',
+            'required' => false
+        ));
+
+        $builder->add('submit', 'submit');
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(
+            array(
+                'data_class' => 'Entity\CurriculumCategory'
+            )
+        );
+    }
+
+    public function getName()
+    {
+        return 'curriculumCategory';
+    }
+}

+ 54 - 0
src/ChamiloLMS/Form/CurriculumItemRelUserCollectionType.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace ChamiloLMS\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+use Entity;
+
+class CurriculumItemRelUserCollectionType extends AbstractType
+{
+    public $itemId;
+    public $userItems;
+
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder->add('userItems', 'collection',
+            array (
+                'type' => new CurriculumItemRelUserType($this->itemId),
+                'allow_add' => true,
+                'allow_delete' => true,
+                'by_reference' => false,
+                'prototype' => true,
+                'prototype_name' => '__name__',
+                'options' => array(
+                    // options on the rendered CurriculumItemRelUserType
+                ),
+                'label' => ' '
+            )
+        );
+        //$builder->add('item_id', 'hidden');
+        //$builder->add('submit', 'submit', array('attr' => array('class' => 'btn btn-success', 'onclick' => 'save(this);')));
+    }
+
+    public function __construct($itemId = null)
+    {
+        $this->itemId = $itemId;
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(
+            array(
+                'data_class' => 'Entity\CurriculumItem'
+            )
+        );
+    }
+
+
+    public function getName()
+    {
+        return 'CurriculumItemRelUserCollection';
+    }
+}

+ 43 - 0
src/ChamiloLMS/Form/CurriculumItemRelUserType.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace ChamiloLMS\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+use Entity;
+
+
+class CurriculumItemRelUserType extends AbstractType
+{
+    public $itemId;
+
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder->add('description', 'text');
+        $builder->add('item_id', 'hidden', array('attr' => array('value' => $this->itemId)));
+        //$builder->add('user_id', 'hidden');
+        //$builder->add('order_id', 'hidden');
+        //$builder->add('submit', 'submit');
+
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(
+            array(
+                'data_class' => 'Entity\CurriculumItemRelUser'
+            )
+        );
+    }
+
+    public function getName()
+    {
+        return 'curriculumItemRelUser';
+    }
+
+    public function __construct($itemId = null)
+    {
+        $this->itemId = $itemId;
+    }
+}

+ 49 - 0
src/ChamiloLMS/Form/CurriculumItemType.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace ChamiloLMS\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+use Entity;
+
+class CurriculumItemType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        //$builderData = $builder->getData();
+        /*$parentIdDisabled = false;
+        if (!empty($builderData)) {
+            $parentIdDisabled = true;
+        }*/
+
+        $builder->add('title', 'text');
+        $builder->add('score', 'text');
+        $builder->add('max_repeat', 'text');
+
+        $builder->add('category', 'entity', array(
+            'class' => 'Entity\CurriculumCategory',
+            'query_builder' => function($repository) {
+                return $repository->createQueryBuilder('p')
+                    ->orderBy('p.title', 'ASC');
+            },
+            'property' => 'title',
+            'required' => false
+        ));
+        $builder->add('submit', 'submit');
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(
+            array(
+                'data_class' => 'Entity\CurriculumItem'
+            )
+        );
+    }
+
+    public function getName()
+    {
+        return 'curriculumItem';
+    }
+}