* * Este programa é software livre; você pode redistribuí-lo e/ou modificá-lo * sob os termos da Licença Pública Geral GNU conforme publicada pela Free * Software Foundation; tanto a versão 2 da Licença, como (a seu critério) * qualquer versão posterior. * * Este programa é distribuí­do na expectativa de que seja útil, porém, SEM * NENHUMA GARANTIA; nem mesmo a garantia implí­cita de COMERCIABILIDADE OU * ADEQUAÇÃO A UMA FINALIDADE ESPECÍFICA. Consulte a Licença Pública Geral * do GNU para mais detalhes. * * Você deve ter recebido uma cópia da Licença Pública Geral do GNU junto * com este programa; se não, escreva para a Free Software Foundation, Inc., no * endereço 59 Temple Street, Suite 330, Boston, MA 02111-1307 USA. * * @author Eriksen Costa Paixão * @category i-Educar * @license @@license@@ * @package Avaliacao * @subpackage Modules * @since Arquivo disponível desde a versão 1.1.0 * @version $Id$ */ require_once 'CoreExt/Configurable.php'; require_once 'CoreExt/Entity.php'; require_once 'App/Model/IedFinder.php'; require_once 'App/Model/Matricula.php'; require_once 'App/Model/MatriculaSituacao.php'; /** * Avaliacao_Service_Boletim class. * * Implementa uma API orientada a serviços (Service Layer Pattern * {@link http://martinfowler.com/eaaCatalog/serviceLayer.html}). * * @author Eriksen Costa Paixão * @category i-Educar * @license @@license@@ * @package Avaliacao * @subpackage Modules * @since Classe disponível desde a versão 1.1.0 * @todo Substituir todos os usos literais de 'Rc' e 'An' por constantes * ou por um novo CoreExt_Enum * @todo Criar método que retorna o conjunto de faltas de acordo com o * tipo de presença da regra, refatorando a série de condicionais * existentes em métodos como getSituacaoFaltas() * @version @@package_version@@ */ class Avaliacao_Service_Boletim implements CoreExt_Configurable { /** * Valores escalares. * @var array */ protected $_options = array( 'matricula' => NULL, 'etapas' => NULL, 'usuario' => NULL ); /** * Instância da regra de avaliação, com o qual o serviço irá utilizar para * decidir o fluxo da lógica. * @var RegraAvaliacao_Model_Regra */ protected $_regra = NULL; /** * @var ComponenteCurricular_Model_ComponenteDataMapper */ protected $_componenteDataMapper = NULL; /** * @var ComponenteCurricular_Model_TurmaDataMapper */ protected $_componenteTurmaDataMapper = NULL; /** * @var RegraAvaliacao_Model_RegraDataMapper */ protected $_regraDataMapper = NULL; /** * @var Avaliacao_Model_NotaAlunoDataMapper */ protected $_notaAlunoDataMapper = NULL; /** * @var Avaliacao_Model_FaltaAlunoDataMapper */ protected $_faltaAlunoDataMapper = NULL; /** * @var Avaliacao_Model_ParecerDescritivoAlunoDataMapper */ protected $_parecerDescritivoAlunoDataMapper = NULL; /** * @var Avaliacao_Model_NotaComponenteDataMapper */ protected $_notaComponenteDataMapper = NULL; /** * @var Avaliacao_Model_FaltaAbstractDataMapper */ protected $_faltaAbstractDataMapper = NULL; /** * @var Avaliacao_Model_NotaComponenteMediaDataMapper */ protected $_notaComponenteMediaDataMapper = NULL; /** * @var Avaliacao_Model_ParecerDescritivoAbstractDataMapper */ protected $_parecerDescritivoAbstractDataMapper = NULL; /** * Uma instância de Avaliacao_Model_NotaAluno, que é a entrada que contém * o cruzamento de matrícula com as notas do aluno nos diversos componentes * cursados. * * @var Avaliacao_Model_NotaAluno */ protected $_notaAluno = NULL; /** * Uma instância de Avaliacao_Model_FaltaAluno, que é a entrada que contém * o cruzamento de matrícula com as faltas do aluno nos diversos componentes * cursados ou no geral. * * @var Avaliacao_Model_NotaAluno */ protected $_faltaAluno = NULL; /** * Uma instância de Avaliacao_Model_ParecerDescritivoAluno, que é a entrada * que contém o cruzamento de matrícula com os pareceres do aluno nos diversos * componentes cursados ou no geral. * * @var Avaliacao_Model_ParecerDescritivoAluno */ protected $_parecerDescritivoAluno = NULL; /** * Componentes que o aluno cursa, indexado pelo id de * ComponenteCurricular_Model_Componente. * @var array */ protected $_componentes = NULL; /** * Notas do aluno nos componentes cursados. * @var array */ protected $_notasComponentes = array(); /** * Médias do aluno nos componentes cursados. * @var array */ protected $_mediasComponentes = array(); /** * Notas adicionadas no boletim para inclusão ou edição. * @var array */ protected $_notas = array(); /** * Faltas do aluno nos componentes cursados. * @var array */ protected $_faltasComponentes = array(); /** * Faltas do aluno no geral. * @var array */ protected $_faltasGerais = array(); /** * Faltas adicionadas no boletim para inclusão ou edição. * @var array */ protected $_faltas = array(); /** * Pareceres descritivos adicionados no boletim para inclusão ou edição. * @var array */ protected $_pareceres = array(); /** * Pareceres descritivos do aluno nos componentes cursados. * @var array */ protected $_pareceresComponentes = array(); /** * Pareceres descritivos do aluno no geral. * @var array */ protected $_pareceresGerais = array(); /** * Validadores para instâncias de Avaliacao_Model_FaltaAbstract e * Avaliacao_Model_NotaComponente. * * @see Avaliacao_Service_Boletim#_addValidators() * @var array */ protected $_validators = NULL; /** * Validadores para uma instância de Avaliacao_Model_ParecerDescritivoAbstract * adicionada no boletim. * * @see Avaliacao_Service_Boletim#_addParecerValidators() * @var array */ protected $_parecerValidators = NULL; /** * Prioridade da situação da matrícula, usado para definir a situação * das notas e faltas. * @var array */ protected $_situacaoPrioridade = array( App_Model_MatriculaSituacao::EM_ANDAMENTO => 1, App_Model_MatriculaSituacao::EM_EXAME => 2, App_Model_MatriculaSituacao::REPROVADO => 3, App_Model_MatriculaSituacao::APROVADO_APOS_EXAME => 4, App_Model_MatriculaSituacao::APROVADO => 5 ); /** * Construtor. * * Opções de configuração: * - matricula (int), obrigatória * - ComponenteDataMapper (Componente_Model_ComponenteDataMapper), opcional * - RegraDataMapper (Regra_Model_RegraDataMapper), opcional * - NotaAlunoDataMapper (Avaliacao_Model_NotaAlunoDataMapper), opcional * * @param array $options */ public function __construct(array $options = array()) { $this->setOptions($options) ->_setMatriculaInfo() ->_loadNotaComponenteCurricular() ->_loadFalta() ->_loadParecerDescritivo(); } /** * @see CoreExt_Configurable#setOptions() */ public function setOptions(array $options = array()) { if (!isset($options['matricula'])) { require_once 'CoreExt/Service/Exception.php'; throw new CoreExt_Service_Exception('É necessário informar o número de ' . 'matrícula do aluno.'); } if (isset($options['ComponenteDataMapper'])) { $this->setComponenteDataMapper($options['ComponenteDataMapper']); unset($options['ComponenteDataMapper']); } if (isset($options['ComponenteTurmaDataMapper'])) { $this->setComponenteTurmaDataMapper($options['ComponenteTurmaDataMapper']); unset($options['ComponenteTurmaDataMapper']); } if (isset($options['RegraDataMapper'])) { $this->setRegraDataMapper($options['RegraDataMapper']); unset($options['RegraDataMapper']); } if (isset($options['NotaAlunoDataMapper'])) { $this->setNotaAlunoDataMapper($options['NotaAlunoDataMapper']); unset($options['NotaAlunoDataMapper']); } if (isset($options['NotaComponenteDataMapper'])) { $this->setNotaComponenteDataMapper($options['NotaComponenteDataMapper']); unset($options['NotaComponenteDataMapper']); } if (isset($options['NotaComponenteMediaDataMapper'])) { $this->setNotaComponenteMediaDataMapper($options['NotaComponenteMediaDataMapper']); unset($options['NotaComponenteMediaDataMapper']); } if (isset($options['FaltaAlunoDataMapper'])) { $this->setFaltaAlunoDataMapper($options['FaltaAlunoDataMapper']); unset($options['FaltaAlunoDataMapper']); } if (isset($options['FaltaAbstractDataMapper'])) { $this->setFaltaAbstractDataMapper($options['FaltaAbstractDataMapper']); unset($options['FaltaAbstractDataMapper']); } if (isset($options['ParecerDescritivoAlunoDataMapper'])) { $this->setParecerDescritivoAlunoDataMapper($options['ParecerDescritivoAlunoDataMapper']); unset($options['ParecerDescritivoAlunoDataMapper']); } if (isset($options['ParecerDescritivoAbstractDataMapper'])) { $this->setParecerDescritivoAbstractDataMapper($options['ParecerDescritivoAbstractDataMapper']); unset($options['ParecerDescritivoAbstractDataMapper']); } $defaultOptions = array_keys($this->getOptions()); $passedOptions = array_keys($options); if (0 < count(array_diff($passedOptions, $defaultOptions))) { throw new InvalidArgumentException( sprintf('A classe %s não suporta as opções: %s.', get_class($this), implode(', ', $passedOptions)) ); } $this->_options = array_merge($this->getOptions(), $options); return $this; } /** * @see CoreExt_Configurable#getOptions() */ public function getOptions() { return $this->_options; } /** * Setter. * @param string $key * @param mixed $value * @return Avaliacao_Service_Boletim Provê interface fluída */ public function setOption($key, $value) { $this->_options[$key] = $value; return $this; } /** * Getter. * @param string $key * @return mixed */ public function getOption($key) { return $this->_options[$key]; } /** * Setter. * @param ComponenteCurricular_Model_ComponenteDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setComponenteDataMapper(ComponenteCurricular_Model_ComponenteDataMapper $mapper) { $this->_componenteDataMapper = $mapper; return $this; } /** * Getter. * @return ComponenteCurricular_Model_ComponenteDataMapper */ public function getComponenteDataMapper() { if (is_null($this->_componenteDataMapper)) { require_once 'ComponenteCurricular/Model/ComponenteDataMapper.php'; $this->setComponenteDataMapper(new ComponenteCurricular_Model_ComponenteDataMapper()); } return $this->_componenteDataMapper; } /** * Setter. * @param ComponenteCurricular_Model_TurmaDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setComponenteTurmaDataMapper(ComponenteCurricular_Model_TurmaDataMapper $mapper) { $this->_componenteTurmaDataMapper = $mapper; return $this; } /** * Getter. * @return ComponenteCurricular_Model_TurmaDataMapper */ public function getComponenteTurmaDataMapper() { if (is_null($this->_componenteTurmaDataMapper)) { require_once 'ComponenteCurricular/Model/TurmaDataMapper.php'; $this->setComponenteTurmaDataMapper(new ComponenteCurricular_Model_TurmaDataMapper()); } return $this->_componenteTurmaDataMapper; } /** * Setter. * @param RegraAvaliacao_Model_RegraDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setRegraDataMapper(RegraAvaliacao_Model_RegraDataMapper $mapper) { $this->_regraDataMapper = $mapper; return $this; } /** * Getter. * @return RegraAvaliacao_Model_RegraDataMapper */ public function getRegraDataMapper() { if (is_null($this->_regraDataMapper)) { require_once 'RegraAvaliacao/Model/RegraDataMapper.php'; $this->setRegraDataMapper(new RegraAvaliacao_Model_RegraDataMapper()); } return $this->_regraDataMapper; } /** * Setter. * @param Avaliacao_Model_NotaAlunoDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setNotaAlunoDataMapper(Avaliacao_Model_NotaAlunoDataMapper $mapper) { $this->_notaAlunoDataMapper = $mapper; return $this; } /** * Getter. * @return Avaliacao_Model_NotaAlunoDataMapper */ public function getNotaAlunoDataMapper() { if (is_null($this->_notaAlunoDataMapper)) { require_once 'Avaliacao/Model/NotaAlunoDataMapper.php'; $this->setNotaAlunoDataMapper(new Avaliacao_Model_NotaAlunoDataMapper()); } return $this->_notaAlunoDataMapper; } /** * Setter. * @param Avaliacao_Model_NotaComponenteDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setNotaComponenteDataMapper(Avaliacao_Model_NotaComponenteDataMapper $mapper) { $this->_notaComponenteDataMapper = $mapper; return $this; } /** * Getter. * @return Avaliacao_Model_NotaComponenteDataMapper */ public function getNotaComponenteDataMapper() { if (is_null($this->_notaComponenteDataMapper)) { require_once 'Avaliacao/Model/NotaComponenteDataMapper.php'; $this->setNotaComponenteDataMapper(new Avaliacao_Model_NotaComponenteDataMapper()); } return $this->_notaComponenteDataMapper; } /** * Setter. * @param Avaliacao_Model_NotaMediaComponenteDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setNotaComponenteMediaDataMapper(Avaliacao_Model_NotaComponenteMediaDataMapper $mapper) { $this->_notaComponenteMediaDataMapper = $mapper; return $this; } /** * Getter. * @return Avaliacao_Model_NotaComponenteMediaDataMapper */ public function getNotaComponenteMediaDataMapper() { if (is_null($this->_notaComponenteMediaDataMapper)) { require_once 'Avaliacao/Model/NotaComponenteMediaDataMapper.php'; $this->setNotaComponenteMediaDataMapper(new Avaliacao_Model_NotaComponenteMediaDataMapper()); } return $this->_notaComponenteMediaDataMapper; } /** * Setter. * @param Avaliacao_Model_FaltaAlunoDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setFaltaAlunoDataMapper(Avaliacao_Model_FaltaAlunoDataMapper $mapper) { $this->_faltaAlunoDataMapper = $mapper; return $this; } /** * Getter. * @return Avaliacao_Model_NotaAlunoDataMapper */ public function getFaltaAlunoDataMapper() { if (is_null($this->_faltaAlunoDataMapper)) { require_once 'Avaliacao/Model/FaltaAlunoDataMapper.php'; $this->setFaltaAlunoDataMapper(new Avaliacao_Model_FaltaAlunoDataMapper()); } return $this->_faltaAlunoDataMapper; } /** * Setter. * @param Avaliacao_Model_FaltaAbstractDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setFaltaAbstractDataMapper(Avaliacao_Model_FaltaAbstractDataMapper $mapper) { $this->_faltaAbstractDataMapper = $mapper; return $this; } /** * Getter. * @return Avaliacao_Model_FaltaAbstractDataMapper */ public function getFaltaAbstractDataMapper() { if (is_null($this->_faltaAbstractDataMapper)) { switch ($this->getRegra()->get('tipoPresenca')) { case RegraAvaliacao_Model_TipoPresenca::POR_COMPONENTE: require_once 'Avaliacao/Model/FaltaComponenteDataMapper.php'; $class = 'Avaliacao_Model_FaltaComponenteDataMapper'; break; case RegraAvaliacao_Model_TipoPresenca::GERAL: require_once 'Avaliacao/Model/FaltaGeralDataMapper.php'; $class = 'Avaliacao_Model_FaltaGeralDataMapper'; break; } $this->setFaltaAbstractDataMapper(new $class()); } return $this->_faltaAbstractDataMapper; } /** * Setter. * @param Avaliacao_Model_ParecerDescritivoAlunoDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setParecerDescritivoAlunoDataMapper(Avaliacao_Model_ParecerDescritivoAlunoDataMapper $mapper) { $this->_parecerDescritivoAlunoDataMapper = $mapper; return $this; } /** * Getter. * @return Avaliacao_Model_ParecerDescritivoAlunoDataMapper */ public function getParecerDescritivoAlunoDataMapper() { if (is_null($this->_parecerDescritivoAlunoDataMapper)) { require_once 'Avaliacao/Model/ParecerDescritivoAlunoDataMapper.php'; $this->setParecerDescritivoAlunoDataMapper(new Avaliacao_Model_ParecerDescritivoAlunoDataMapper()); } return $this->_parecerDescritivoAlunoDataMapper; } /** * Setter. * @param Avaliacao_Model_ParecerDescritivoAbstractDataMapper $mapper * @return App_Service_Boletim Provê interface fluída */ public function setParecerDescritivoAbstractDataMapper(Avaliacao_Model_ParecerDescritivoAbstractDataMapper $mapper) { $this->_parecerDescritivoAbstractDataMapper = $mapper; return $this; } /** * Getter. * @return Avaliacao_Model_ParecerDescritivoAbstractDataMapper */ public function getParecerDescritivoAbstractDataMapper() { if (is_null($this->_parecerDescritivoAbstractDataMapper)) { $parecerDescritivo = $this->getRegra()->get('parecerDescritivo'); switch($parecerDescritivo) { case RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_GERAL: case RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_GERAL: $filename = 'Avaliacao/Model/ParecerDescritivoGeralDataMapper.php'; $class = 'Avaliacao_Model_ParecerDescritivoGeralDataMapper'; break; case RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_COMPONENTE: case RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_COMPONENTE: $filename = 'Avaliacao/Model/ParecerDescritivoComponenteDataMapper.php'; $class = 'Avaliacao_Model_ParecerDescritivoComponenteDataMapper'; break; } // Se não usar parecer descritivo, retorna NULL if (!isset($filename)) { return NULL; } require_once $filename; $this->setParecerDescritivoAbstractDataMapper(new $class()); } return $this->_parecerDescritivoAbstractDataMapper; } /** * Retorna as instâncias de Avaliacao_Model_NotaComponente do aluno. * @return array */ public function getNotasComponentes() { return $this->_notasComponentes; } /** * Retorna as instâncias de Avaliacao_Model_NotaComponenteMedia do aluno. * @return array */ public function getMediasComponentes() { return $this->_mediasComponentes; } /** * Retorna as instâncias de Avaliacao_Model_FaltaComponente do aluno. * @return array */ public function getFaltasComponentes() { return $this->_faltasComponentes; } /** * Retorna as instâncias de Avaliacao_Model_FaltaGeral do aluno. * @return array */ public function getFaltasGerais() { return $this->_faltasGerais; } /** * Retorna as instâncias de Avaliacao_Model_ParecerDescritivoComponente do * aluno. * @return array */ public function getPareceresComponentes() { return $this->_pareceresComponentes; } /** * Retorna as instâncias de Avaliacao_Model_ParecerDescritivoGeral do aluno. * @return array */ public function getPareceresGerais() { return $this->_pareceresGerais; } /** * Retorna uma instância de Avaliacao_Model_NotaComponente. * * @param int $id O identificador de ComponenteCurricular_Model_Componente * @param int $etapa A etapa para o qual a nota foi lançada * @return Avaliacao_Model_NotaComponente|NULL */ public function getNotaComponente($id, $etapa = 1) { $componentes = $this->getNotasComponentes(); if (!isset($componentes[$id])) { return NULL; } $notasComponente = $componentes[$id]; foreach ($notasComponente as $nota) { if ($nota->etapa == $etapa) { return $nota; } } return NULL; } /** * Retorna uma instância de Avaliacao_Model_FaltaAbstract. * * @param int $etapa A etapa para o qual a falta foi lançada * @param int $id O identificador de ComponenteCurricular_Model_Componente * @return Avaliacao_Model_FaltaAbstract|NULL */ public function getFalta($etapa = 1, $id = NULL) { if ($this->getRegra()->get('tipoPresenca') == RegraAvaliacao_Model_TipoPresenca::POR_COMPONENTE) { $faltas = $this->getFaltasComponentes(); if (!isset($faltas[$id])) { return NULL; } $faltas = $faltas[$id]; } else { $faltas = $this->getFaltasGerais(); } foreach ($faltas as $falta) { if ($falta->etapa == $etapa) { return $falta; } } return NULL; } /** * Retorna uma instância de Avaliacao_Model_ParecerDescritivoAbstract. * * @param int $etapa A etapa para o qual o parecer foi lançado * @param int $id O identificador de ComponenteCurricular_Model_Componente * @return Avaliacao_Model_ParecerAbstract|NULL */ public function getParecerDescritivo($etapa = 1, $id = NULL) { $parecerDescritivo = $this->getRegra()->get('parecerDescritivo'); $gerais = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_GERAL ); $componentes = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_COMPONENTE, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_COMPONENTE ); if (in_array($parecerDescritivo, $gerais)) { $pareceres = $this->getPareceresGerais(); } elseif (in_array($parecerDescritivo, $componentes)) { $pareceres = $this->getPareceresComponentes(); if (!isset($pareceres[$id])) { return NULL; } $pareceres = $pareceres[$id]; } foreach ($pareceres as $parecer) { if ($parecer->etapa == $etapa) { return $parecer; } } return NULL; } /** * Setter. * @return App_Service_Boletim Provê interface fluída */ protected function _setMatriculaInfo() { $codMatricula = $this->getOption('matricula'); $this->_setRegra(App_Model_IedFinder::getRegraAvaliacaoPorMatricula( $codMatricula, $this->getRegraDataMapper() )) ->_setComponentes(App_Model_IedFinder::getComponentesPorMatricula( $codMatricula, $this->getComponenteDataMapper(), $this->getComponenteTurmaDataMapper() )); // Valores scalar de referência $matricula = App_Model_IedFinder::getMatricula($codMatricula); $etapas = App_Model_IedFinder::getQuantidadeDeModulosMatricula($codMatricula); $this->setOption('matriculaData', $matricula); $this->setOption('aprovado', $matricula['aprovado']); $this->setOption('cursoHoraFalta', $matricula['curso_hora_falta']); $this->setOption('cursoCargaHoraria', $matricula['curso_carga_horaria']); $this->setOption('serieCargaHoraria', $matricula['serie_carga_horaria']); $this->setOption('serieDiasLetivos', $matricula['serie_dias_letivos']); $this->setOption('etapas', $etapas); return $this; } /** * Carrega todas as notas e médias já lançadas para a matrícula atual. * * @param bool $loadMedias FALSE caso não seja necessário carregar as médias * @return App_Service_Boletim Provê interface fluída */ protected function _loadNotaComponenteCurricular($loadMedias = TRUE) { // Cria uma entrada no boletim caso o aluno/matrícula não a tenha if (!$this->hasNotaAluno()) { $this->_createNotaAluno(); } // Senão tiver, vai criar $notaAluno = $this->_getNotaAluno(); $notas = $this->getNotaComponenteDataMapper()->findAll( array(), array('notaAluno' => $notaAluno->id), array('etapa' => 'ASC') ); // Separa cada nota em um array indexado pelo identity do componente $notasComponentes = array(); foreach ($notas as $nota) { $notasComponentes[$nota->get('componenteCurricular')][] = $nota; } $this->_notasComponentes = $notasComponentes; if (FALSE == $loadMedias) { return $this; } return $this->_loadNotaComponenteCurricularMedia(); } /** * Carrega as médias dos componentes curriculares já lançadas. * @return App_Service_Boletim Provê interface fluída */ protected function _loadNotaComponenteCurricularMedia() { $notaAluno = $this->_getNotaAluno(); $medias = $this->getNotaComponenteMediaDataMapper()->findAll( array(), array('notaAluno' => $notaAluno->id) ); $mediasComponentes = array(); foreach ($medias as $media) { $mediasComponentes[$media->get('componenteCurricular')][] = $media; } $this->_mediasComponentes = $mediasComponentes; return $this; } /** * Carrega as faltas do aluno, sejam gerais ou por componente. * @return App_Service_Boletim Provê interface fluída */ protected function _loadFalta() { // Cria uma entrada no boletim caso o aluno/matrícula não a tenha if (!$this->hasFaltaAluno()) { $this->_createFaltaAluno(); } // Senão tiver, vai criar $faltaAluno = $this->_getFaltaAluno(); // Carrega as faltas já lançadas $faltas = $this->getFaltaAbstractDataMapper()->findAll( array(), array('faltaAluno' => $faltaAluno->id), array('etapa' => 'ASC') ); // Se a falta for do tipo geral, popula um array indexado pela etapa if ($faltaAluno->get('tipoFalta') == RegraAvaliacao_Model_TipoPresenca::GERAL) { $faltasGerais = array(); foreach ($faltas as $falta) { $faltasGerais[$falta->etapa] = $falta; } $this->_faltasGerais = $faltasGerais; } // Separa cada nota em um array indexado pelo identity field do componente elseif ($faltaAluno->get('tipoFalta') == RegraAvaliacao_Model_TipoPresenca::POR_COMPONENTE) { $faltasComponentes = array(); foreach ($faltas as $falta) { $faltasComponentes[$falta->get('componenteCurricular')][] = $falta; } $this->_faltasComponentes = $faltasComponentes; } return $this; } /** * Carrega os pareceres do aluno, sejam gerais ou por componentes. * @return App_Service_Boletim Provê interface fluída */ protected function _loadParecerDescritivo() { if ($this->getRegra()->get('parecerDescritivo') == RegraAvaliacao_Model_TipoParecerDescritivo::NENHUM) { return $this; } if (!$this->hasParecerDescritivoAluno()) { $this->_createParecerDescritivoAluno(); } $parecerDescritivoAluno = $this->_getParecerDescritivoAluno(); $pareceres = $this->getParecerDescritivoAbstractDataMapper()->findAll( array(), array('parecerDescritivoAluno' => $parecerDescritivoAluno->id), array('etapa' => 'ASC') ); $gerais = array( RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_GERAL ); $componentes = array( RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_COMPONENTE, RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_COMPONENTE ); $parecerDescritivo = $this->getRegra()->get('parecerDescritivo'); if (in_array($parecerDescritivo, $gerais)) { $pareceresGerais = array(); foreach ($pareceres as $parecer) { $pareceresGerais[$parecer->etapa] = $parecer; } $this->_pareceresGerais = $pareceresGerais; } elseif (in_array($parecerDescritivo, $componentes)) { $pareceresComponentes = array(); foreach ($pareceres as $parecer) { $pareceresComponentes[$parecer->get('componenteCurricular')][] = $parecer; } $this->_pareceresComponentes = $pareceresComponentes; } return $this; } /** * Setter. * @param RegraAvaliacao_Model_Regra $regra * @return App_Service_Boletim Provê interface fluída */ protected function _setRegra(RegraAvaliacao_Model_Regra $regra) { $this->_regra = $regra; return $this; } /** * Getter. * @return RegraAvaliacao_Model_Regra */ public function getRegra() { return $this->_regra; } /** * Setter. * @param array $componentes * @return Avaliacao_Service_Boletim Provê interface fluída */ protected function _setComponentes(array $componentes) { $this->_componentes = $componentes; return $this; } /** * Getter. * @return array */ public function getComponentes() { return $this->_componentes; } /** * Getter. * @return TabelaArredondamento_Model_Tabela */ public function getTabelaArredondamento() { return $this->getRegra()->tabelaArredondamento; } /** * Verifica se a regra de avaliacação possui recuperação final. * @return bool */ public function hasRecuperacao() { if (is_null($this->getRegra()->get('formulaRecuperacao'))) { return FALSE; } return TRUE; } /** * Verifica se o aluno tem notas lançadas. * @return bool */ public function hasNotaAluno() { if (!is_null($this->_getNotaAluno())) { return TRUE; } return FALSE; } function getSituacaoNotaFalta($flagSituacaoNota, $flagSituacaoFalta) { $situacao = new stdClass(); $situacao->situacao = App_Model_MatriculaSituacao::EM_ANDAMENTO; $situacao->aprovado = TRUE; $situacao->andamento = FALSE; $situacao->recuperacao = FALSE; $situacao->retidoFalta = FALSE; switch ($flagSituacaoNota) { case App_Model_MatriculaSituacao::EM_ANDAMENTO: $situacao->aprovado = FALSE; $situacao->andamento = TRUE; break; case App_Model_MatriculaSituacao::APROVADO_APOS_EXAME: $situacao->recuperacao = TRUE; break; case App_Model_MatriculaSituacao::EM_EXAME: $situacao->aprovado = FALSE; $situacao->andamento = TRUE; $situacao->recuperacao = TRUE; break; case App_Model_MatriculaSituacao::REPROVADO: $situacao->aprovado = FALSE; break; } switch ($flagSituacaoFalta) { case App_Model_MatriculaSituacao::EM_ANDAMENTO: $situacao->aprovado = FALSE; $situacao->andamento = TRUE; break; case App_Model_MatriculaSituacao::REPROVADO: $situacao->retidoFalta = TRUE; $situacao->aprovado = FALSE; // Se reprovado por falta, mesmo que falte lançar a nota de exame, considera como reprovado. $situacao->andamento = FALSE; break; case App_Model_MatriculaSituacao::APROVADO: $situacao->retidoFalta = FALSE; break; } // seta situacao geral if ($situacao->andamento and $situacao->recuperacao) $situacao->situacao = App_Model_MatriculaSituacao::EM_EXAME; elseif (! $situacao->andamento and $situacao->aprovado and $situacao->recuperacao) $situacao->situacao = App_Model_MatriculaSituacao::APROVADO_APOS_EXAME; elseif (! $situacao->andamento and $situacao->aprovado) $situacao->situacao = App_Model_MatriculaSituacao::APROVADO; elseif (! $situacao->andamento and (! $situacao->aprovado || $situacao->retidoFalta)) $situacao->situacao = App_Model_MatriculaSituacao::REPROVADO; return $situacao; } /** * Retorna a situação geral do aluno, levando em consideração as situações * das notas (médias) e faltas. O retorno é baseado em booleanos, indicando * se o aluno está aprovado, em andamento, em recuperação ou retido por falta. * * Retorna também a situação das notas e faltas tais quais retornadas pelos * métodos getSituacaoComponentesCurriculares() e getSituacaoFaltas(). * * * aprovado = TRUE; * $situacao->andamento = FALSE; * $situacao->recuperacao = FALSE; * $situacao->retidoFalta = FALSE; * $situacao->nota = $this->getSituacaoComponentesCurriculares(); * $situacao->falta = $this->getSituacaoFaltas(); * * * @return stdClass * @see Avaliacao_Service_Boletim#getSituacaoComponentesCurriculares() * @see Avaliacao_Service_Boletim#getSituacaoFaltas() */ public function getSituacaoAluno() { $situacaoNotas = $this->getSituacaoNotas(); $situacaoFaltas = $this->getSituacaoFaltas(); $situacao = $this->getSituacaoNotaFalta($situacaoNotas->situacao, $situacaoFaltas->situacao); $situacao->nota = $situacaoNotas; $situacao->falta = $situacaoFaltas; return $situacao; } /** * Retorna a situação das notas lançadas para os componentes curriculares cursados pelo aluno. Possui * uma flag "situacao" global, que indica a situação global do aluno, podendo * ser: * * - Em andamento * - Em exame * - Aprovado * - Reprovado * * Esses valores são definidos no enum App_Model_MatriculaSituacao. * * Para cada componente curricular, será indicado a situação do aluno no * componente. * * Esses resultados são retornados como um objeto stdClass que possui dois * atributos: "situacao" e "componentesCurriculares". O primeiro é um tipo * inteiro e o segundo um array indexado pelo id do componente e com um * atributo inteiro "situacao": * * * situacao = App_Model_MatriculaSituacao::APROVADO; * $situacao->componentesCurriculares = array(); * $situacao->componentesCurriculares[1] = new stdClass(); * $situacao->componentesCurriculares[1]->situacao = App_Model_MatriculaSituacao::APROVADO; * * * Esses valores são definidos SOMENTE através da verificação das médias dos * componentes curriculares já avaliados. * * Obs: Anteriormente este metódo se chamava getSituacaoComponentesCurriculares, porem na verdade não retornava a * situação dos componentes curriculares (que seria a situação baseada nas notas e das faltas lançadas) e sim * então foi renomeado este metodo para getSituacaoNotas, para que no metódo getSituacaoComponentesCurriculares * fosse retornado a situação do baseada nas notas e faltas lançadas. * * * @return stdClass|NULL Retorna NULL caso não * @see App_Model_MatriculaSituacao */ public function getSituacaoNotas() { $situacao = new stdClass(); $situacao->situacao = 0; $situacao->componentesCurriculares = array(); // A situação é "aprovado" por padrão $situacaoGeral = App_Model_MatriculaSituacao::APROVADO; if ($this->getRegra()->get('tipoNota') == RegraAvaliacao_Model_Nota_TipoValor::NENHUM) { return $situacao; } // Carrega as médias pois este método pode ser chamado após a chamada a saveNotas() $mediasComponentes = $this->_loadNotaComponenteCurricularMedia() ->getMediasComponentes(); // Se não tiver nenhuma média ou a quantidade for diferente dos componentes // curriculares da matrícula, ainda está em andamento if (0 == count($mediasComponentes) || count($mediasComponentes) != count($this->getComponentes())) { $situacaoGeral = App_Model_MatriculaSituacao::EM_ANDAMENTO; } foreach ($mediasComponentes as $id => $mediaComponente) { $etapa = $mediaComponente[0]->etapa; if ($this->getRegra()->get('tipoNota') == RegraAvaliacao_Model_Nota_TipoValor::NUMERICA) { $media = $mediaComponente[0]->mediaArredondada; } else { $media = $mediaComponente[0]->media; } $situacao->componentesCurriculares[$id] = new stdClass(); $situacao->componentesCurriculares[$id]->situacao = 0; if ($etapa == $this->getOption('etapas') && $media < $this->getRegra()->media && $this->hasRecuperacao()) { $situacao->componentesCurriculares[$id]->situacao = App_Model_MatriculaSituacao::EM_EXAME; } elseif ($etapa == $this->getOption('etapas') && $media < $this->getRegra()->media) { $situacao->componentesCurriculares[$id]->situacao = App_Model_MatriculaSituacao::REPROVADO; } elseif ($etapa == 'Rc' && $media < $this->getRegra()->mediaRecuperacao) { $situacao->componentesCurriculares[$id]->situacao = App_Model_MatriculaSituacao::REPROVADO; } elseif ($etapa == 'Rc' && $media >= $this->getRegra()->mediaRecuperacao && $this->hasRecuperacao()) { $situacao->componentesCurriculares[$id]->situacao = App_Model_MatriculaSituacao::APROVADO_APOS_EXAME; } elseif ($etapa < $this->getOption('etapas') && $etapa != 'Rc') { $situacao->componentesCurriculares[$id]->situacao = App_Model_MatriculaSituacao::EM_ANDAMENTO; } else { $situacao->componentesCurriculares[$id]->situacao = App_Model_MatriculaSituacao::APROVADO; } if ($this->_situacaoPrioritaria($situacao->componentesCurriculares[$id]->situacao, $situacaoGeral)) { $situacaoGeral = $situacao->componentesCurriculares[$id]->situacao; } } // Situação geral $situacao->situacao = $situacaoGeral; return $situacao; } /** * Retorna a situação das faltas do aluno, sejam por componentes curriculares * ou gerais. A situação pode ser: * * - Em andamento * - Aprovado * - Reprovado * * Retorna outros dados interessantes, a maioria informacional para exibição * ao usuário, como a carga horária (geral e por componente), a porcentagem * de presença (geral e por componente), a porcentagem de falta (geral e * por componente), a hora/falta usada para o cálculo das porcentagens e o * total de faltas geral. * * Esses resultados são retornados como um objeto stdClass que possui os * seguintes atributos: * * * situacao = 0; * $presenca->tipoFalta = 0; * $presenca->cargaHoraria = 0; * $presenca->cursoHoraFalta = 0; * $presenca->totalFaltas = 0; * $presenca->horasFaltas = 0; * $presenca->porcentagemFalta = 0; * $presenca->porcentagemPresenca = 0; * $presenca->porcentagemPresencaRegra = 0; * * $presenca->componentesCurriculares = array(); * $presenca->componentesCurriculares[1] = new stdClass(); * $presenca->componentesCurriculares[1]->situacao = 0; * $presenca->componentesCurriculares[1]->horasFaltas = 0; * $presenca->componentesCurriculares[1]->porcentagemFalta = 0; * $presenca->componentesCurriculares[1]->porcentagemPresenca = 0; * * * Esses valores são calculados SOMENTE através das faltas já lançadas. * * @return stdClass * @todo Verificação de situação geral nos moldes dos componentes curriculares * para falta por componente (se 0 ou diferente de componentes matrícula) */ public function getSituacaoFaltas() { $presenca = new stdClass(); $presenca->totalFaltas = 0; $presenca->horasFaltas = 0; $presenca->porcentagemFalta = 0; $presenca->porcentagemPresenca = 0; $presenca->porcentagemPresencaRegra = $this->getRegra()->porcentagemPresenca; $presenca->tipoFalta = $this->getRegra()->get('tipoPresenca'); $presenca->cargaHoraria = $this->getOption('serieCargaHoraria'); $presenca->diasLetivos = $this->getOption('serieDiasLetivos'); $presenca->cursoHoraFalta = $this->getOption('cursoHoraFalta'); $presenca->componentesCurriculares = array(); $presenca->situacao = App_Model_MatriculaSituacao::EM_ANDAMENTO; $etapa = 0; $faltasComponentes = array(); // Carrega faltas lançadas (persistidas) $this->_loadFalta(); $tipoFaltaGeral = $presenca->tipoFalta == RegraAvaliacao_Model_TipoPresenca::GERAL; $tipoFaltaPorComponente = $presenca->tipoFalta == RegraAvaliacao_Model_TipoPresenca::POR_COMPONENTE; if ($tipoFaltaGeral) { $faltas = $this->_faltasGerais; if (0 == count($faltas)) { $total = 0; $etapa = 0; } else { $total = array_sum(CoreExt_Entity::entityFilterAttr($faltas, 'id', 'quantidade')); $etapa = array_pop($faltas)->etapa; } } elseif ($tipoFaltaPorComponente) { $faltas = $this->_faltasComponentes; $total = 0; $etapasComponentes = array(); $faltasComponentes = array(); foreach ($faltas as $key => $falta) { // Total de faltas do componente $componenteTotal = array_sum(CoreExt_Entity::entityFilterAttr($falta, 'id', 'quantidade')); // Pega o id de ComponenteCurricular_Model_Componente da última etapa do array $componenteEtapa = array_pop($falta); $id = $componenteEtapa->get('componenteCurricular'); $etapa = $componenteEtapa->etapa; // Etapas lançadas $etapasComponentes[$etapa] = $etapa; // Usa stdClass como interface de acesso $faltasComponentes[$id] = new stdClass(); $faltasComponentes[$id]->situacao = App_Model_MatriculaSituacao::EM_ANDAMENTO; $faltasComponentes[$id]->horasFaltas = NULL; $faltasComponentes[$id]->porcentagemFalta = NULL; $faltasComponentes[$id]->porcentagemPresenca = NULL; $faltasComponentes[$id]->total = $componenteTotal; //$faltasComponentes[$id]->componenteCurricular = $componenteEtapa; // Calcula a quantidade de horas/faltas no componente $faltasComponentes[$id]->horasFaltas = $this->_calculateHoraFalta($componenteTotal, $presenca->cursoHoraFalta); // Calcula a porcentagem de falta no componente $faltasComponentes[$id]->porcentagemFalta = $this->_calculatePorcentagem($this->_componentes[$id]->cargaHoraria, $faltasComponentes[$id]->horasFaltas, FALSE); // Calcula a porcentagem de presença no componente $faltasComponentes[$id]->porcentagemPresenca = 100 - $faltasComponentes[$id]->porcentagemFalta; // Na última etapa seta situação presença como aprovado ou reprovado. if ($etapa == $this->getOption('etapas') || $etapa == 'Rc') { $aprovado = ($faltasComponentes[$id]->porcentagemPresenca >= $this->getRegra()->porcentagemPresenca); $faltasComponentes[$id]->situacao = $aprovado ? App_Model_MatriculaSituacao::APROVADO : App_Model_MatriculaSituacao::REPROVADO; } // Adiciona a quantidade de falta do componente ao total geral de faltas $total += $componenteTotal; } if (0 == count($faltasComponentes) || count($faltasComponentes) != count($this->getComponentes())) { $etapa = 1; } else { $etapa = min($etapasComponentes); } } // fim if por_componente $presenca->totalFaltas = $total; $presenca->horasFaltas = $this->_calculateHoraFalta($total, $presenca->cursoHoraFalta); if ($tipoFaltaGeral) { $presenca->porcentagemFalta = $this->_calculatePorcentagem($presenca->diasLetivos, $presenca->totalFaltas, FALSE); } elseif ($tipoFaltaPorComponente) { $presenca->porcentagemFalta = $this->_calculatePorcentagem($presenca->cargaHoraria, $presenca->horasFaltas, FALSE); } $presenca->porcentagemPresenca = 100 - $presenca->porcentagemFalta; $presenca->componentesCurriculares = $faltasComponentes; // Na última etapa seta situação presença como aprovado ou reprovado. if ($etapa == $this->getOption('etapas') || $etapa === 'Rc') { $aprovado = ($presenca->porcentagemPresenca >= $this->getRegra()->porcentagemPresenca); $presenca->situacao = $aprovado ? App_Model_MatriculaSituacao::APROVADO : App_Model_MatriculaSituacao::REPROVADO; } return $presenca; } /** * Retorna a situação dos componentes curriculares cursados pelo aluno. Possui * uma flag "situacao" global, que indica a situação global do aluno, podendo * ser: * * - Em andamento * - Em exame * - Aprovado * - Reprovado * * Esses valores são definidos no enum App_Model_MatriculaSituacao. * * Para cada componente curricular, será indicado a situação do aluno no * componente. * * Esses resultados são retornados como um objeto stdClass que possui dois * atributos: "situacao" e "componentesCurriculares". O primeiro é um tipo * inteiro e o segundo um array indexado pelo id do componente e com um * atributo inteiro "situacao": * * * situacao = App_Model_MatriculaSituacao::APROVADO; * $situacao->componentesCurriculares = array(); * $situacao->componentesCurriculares[1] = new stdClass(); * $situacao->componentesCurriculares[1]->situacao = App_Model_MatriculaSituacao::APROVADO; * * * Esses valores são definidos através da verificação das médias dos * componentes curriculares já avaliados e das faltas lançadas. * * Obs: Anteriormente este metódo SOMENTE verificava a situação baseando-se nas médias lançadas, * porem o mesmo foi alterado para verificar a situação baseada nas notas e faltas lançadas. * * A implementa antiga deste metodo esta contida no metodo getSituacaoNotas * * @return stdClass|NULL Retorna NULL caso não * @see App_Model_MatriculaSituacao */ public function getSituacaoComponentesCurriculares() { $situacao = new stdClass(); $situacao->situacao = App_Model_MatriculaSituacao::APROVADO; $situacao->componentesCurriculares = array(); $situacaoNotas = $this->getSituacaoNotas(); $situacaoFaltas = $this->getSituacaofaltas(); foreach($situacaoNotas->componentesCurriculares as $ccId => $situacaoNotaCc) { // seta tipos nota, falta $tipoNotaNenhum = $this->getRegra()->get('tipoNota') == RegraAvaliacao_Model_Nota_TipoValor::NENHUM; $tipoFaltaPorComponente = $this->getRegra()->get('tipoPresenca') == RegraAvaliacao_Model_TipoPresenca::POR_COMPONENTE; // inicializa situacaoFaltaCc a ser usado caso tipoFaltaPorComponente $situacaoFaltaCc = new stdClass(); $situacaoFaltaCc->situacao = App_Model_MatriculaSituacao::EM_ANDAMENTO; // caso possua situacaoFalta para o componente substitui situacao inicializada if ($tipoFaltaPorComponente and isset($situacaoFaltas->componentesCurriculares[$ccId])) $situacaoFaltaCc = $situacaoFaltas->componentesCurriculares[$ccId]; // pega situação nota geral ou do componente if ($tipoNotaNenhum) $situacaoNota = $situacaoNotas->situacao; else $situacaoNota = $situacaoNotaCc->situacao; // pega situacao da falta componente ou geral. if($tipoFaltaPorComponente) $situacaoFalta = $situacaoFaltas->componentesCurriculares[$ccId]->situacao; else $situacaoFalta = $situacaoFaltas->situacao; $situacao->componentesCurriculares[$ccId] = $this->getSituacaoNotaFalta($situacaoNota, $situacaoFalta); } // #FIXME verificar porque para regras sem nota, não é retornado a situacao. return $situacao; } /** * Verifica se uma determinada situação tem prioridade sobre a outra. * * @param int $item1 * @param int $item2 * @return bool */ protected function _situacaoPrioritaria($item1, $item2) { return ($this->_situacaoPrioridade[$item1] <= $this->_situacaoPrioridade[$item2]); } /** * Setter. * @param Avaliacao_Model_NotaAluno $nota * @return Avaliacao_Service_Boletim Provê interface fluída */ protected function _setNotaAluno(Avaliacao_Model_NotaAluno $nota) { $this->_notaAluno = $nota; return $this; } /** * Getter. * @return Avaliacao_Model_NotaAluno|NULL */ protected function _getNotaAluno() { if (!is_null($this->_notaAluno)) { return $this->_notaAluno; } $notaAluno = $this->getNotaAlunoDataMapper()->findAll( array(), array('matricula' => $this->getOption('matricula')) ); if (0 == count($notaAluno)) { return NULL; } $this->_setNotaAluno($notaAluno[0]); return $this->_notaAluno; } /** * Cria e persiste uma instância de Avaliacao_Model_NotaAluno. * @return bool */ protected function _createNotaAluno() { $notaAluno = new Avaliacao_Model_NotaAluno(); $notaAluno->matricula = $this->getOption('matricula'); return $this->getNotaAlunoDataMapper()->save($notaAluno); } /** * Verifica se existe alguma instância de Avaliacao_Model_NotaComponente para * um determinado componente curricular já persistida. * * @param int $id * @return bool */ protected function _hasNotaComponente($id) { $notasComponentes = $this->getNotasComponentes(); if (!isset($notasComponentes[$id])) { return FALSE; } return TRUE; } /** * Retorna o field identity de um componente curricular de uma instância de * Avaliacao_Model_NotaComponente já esteja persistida. * * @param Avaliacao_Model_NotaComponente $instance * @return int|NULL Retorna NULL caso a instância não tenha sido lançada */ protected function _getNotaIdEtapa(Avaliacao_Model_NotaComponente $instance) { $componenteCurricular = $instance->get('componenteCurricular'); if (!$this->_hasNotaComponente($componenteCurricular)) { return NULL; } $notasComponentes = $this->getNotasComponentes(); foreach ($notasComponentes[$componenteCurricular] as $notaComponente) { if ($instance->etapa == $notaComponente->etapa) { return $notaComponente->id; } } return NULL; } /** * Verifica se o aluno tem faltas lançadas. * @return bool */ public function hasFaltaAluno() { if (!is_null($this->_getFaltaAluno())) { return TRUE; } return FALSE; } /** * Setter. * @param Avaliacao_Model_FaltaAluno $falta * @return Avaliacao_Service_Boletim Provê interface fluída */ protected function _setFaltaAluno(Avaliacao_Model_FaltaAluno $falta) { $this->_faltaAluno = $falta; $tipoFaltaAtual = $this->_faltaAluno->get('tipoFalta'); $tipoFaltaRegraAvaliacao = $this->getRegra()->get('tipoPresenca'); if ($tipoFaltaAtual != $tipoFaltaRegraAvaliacao){ $this->_faltaAluno->tipoFalta = $tipoFaltaRegraAvaliacao; $this->getFaltaAlunoDataMapper()->save($this->_faltaAluno); } return $this; } /** * Getter. * @return Avaliacao_Model_FaltaAluno|NULL */ protected function _getFaltaAluno() { if (!is_null($this->_faltaAluno)) { return $this->_faltaAluno; } $faltaAluno = $this->getFaltaAlunoDataMapper()->findAll( array(), array('matricula' => $this->getOption('matricula')) ); if (0 == count($faltaAluno)) { return NULL; } $this->_setFaltaAluno($faltaAluno[0]); return $this->_faltaAluno; } /** * Cria e persiste uma instância de Avaliacao_Model_NotaAluno. * @return bool */ protected function _createFaltaAluno() { $faltaAluno = new Avaliacao_Model_FaltaAluno(); $faltaAluno->matricula = $this->getOption('matricula'); $faltaAluno->tipoFalta = $this->getRegra()->get('tipoPresenca'); return $this->getFaltaAlunoDataMapper()->save($faltaAluno); } /** * Verifica se existe alguma instância de Avaliacao_Model_FaltaGeral já * persistida. * * @return bool */ protected function _hasFaltaGeral() { $faltasGerais = $this->getFaltasGerais(); if (0 == count($faltasGerais)) { return FALSE; } return TRUE; } /** * Verifica se existe alguma instância de Avaliacao_Model_FaltaComponente para * um determinado componente curricular já persistida. * * @param int $id * @return bool */ protected function _hasFaltaComponente($id) { $faltasComponentes = $this->getFaltasComponentes(); if (!isset($faltasComponentes[$id])) { return FALSE; } return TRUE; } /** * Verifica se existe alguma instância de Avaliacao_Model_FaltaAbstract já * persistida em uma determinada etapa e retorna o field identity. * * @param Avaliacao_Model_FaltaAbstract $instance * @return int|NULL */ protected function _getFaltaIdEtapa(Avaliacao_Model_FaltaAbstract $instance) { $etapa = $instance->etapa; if (!is_null($instance) && $this->_getFaltaAluno()->get('tipoFalta') == RegraAvaliacao_Model_TipoPresenca::POR_COMPONENTE) { $componenteCurricular = $instance->get('componenteCurricular'); if (!$this->_hasFaltaComponente($componenteCurricular)) { return NULL; } $faltasComponentes = $this->getFaltasComponentes(); foreach ($faltasComponentes[$componenteCurricular] as $faltaComponente) { if ($etapa == $faltaComponente->etapa) { return $faltaComponente->id; } } } elseif ($this->_getFaltaAluno()->get('tipoFalta') == RegraAvaliacao_Model_TipoPresenca::GERAL) { if (!$this->_hasFaltaGeral()) { return NULL; } $faltasGerais = $this->getFaltasGerais(); if (isset($faltasGerais[$etapa])) { return $faltasGerais[$etapa]->id; } } return NULL; } /** * Verifica se o aluno tem pareceres lançados. * @return bool */ public function hasParecerDescritivoAluno() { if (!is_null($this->_getParecerDescritivoAluno())) { return TRUE; } return FALSE; } /** * Setter. * @param Avaliacao_Model_ParecerDescritivoAluno $parecerDescritivoAluno * @return Avaliacao_Service_Boletim Provê interface fluída */ protected function _setParecerDescritivoAluno(Avaliacao_Model_ParecerDescritivoAluno $parecerDescritivoAluno) { $this->_parecerDescritivoAluno = $parecerDescritivoAluno; return $this; } /** * Getter. * @return Avaliacao_Model_ParecerDescritivoAluno|NULL */ protected function _getParecerDescritivoAluno() { if (!is_null($this->_parecerDescritivoAluno)) { return $this->_parecerDescritivoAluno; } $parecerDescritivoAluno = $this->getParecerDescritivoAlunoDataMapper()->findAll( array(), array('matricula' => $this->getOption('matricula')) ); if (0 == count($parecerDescritivoAluno)) { return NULL; } $this->_setParecerDescritivoAluno($parecerDescritivoAluno[0]); return $this->_parecerDescritivoAluno; } /** * Cria e persiste uma instância de Avaliacao_Model_ParecerDescritivoAluno. * @return bool */ protected function _createParecerDescritivoAluno() { $parecerDescritivoAluno = new Avaliacao_Model_ParecerDescritivoAluno(); $parecerDescritivoAluno->matricula = $this->getOption('matricula'); $parecerDescritivoAluno->parecerDescritivo = $this->getRegra()->get('parecerDescritivo'); return $this->getParecerDescritivoAlunoDataMapper()->save($parecerDescritivoAluno); } /** * Adiciona um array de instâncias Avaliacao_Model_NotaComponente. * * @param array $notas * @return Avaliacao_Service_Boletim Provê interface fluída */ public function addNotas(array $notas) { foreach ($notas as $nota) { $this->addNota($nota); } return $this; } /** * Verifica se existe alguma instância de Avaliacao_Model_ParecerDescritivoComponente * persistida para o aluno. * * @param int $id Field identity de ComponenteCurricular_Model_Componente * @return bool */ protected function _hasParecerComponente($id) { $pareceresComponentes = $this->getPareceresComponentes(); if (!isset($pareceresComponentes[$id])) { return FALSE; } return TRUE; } /** * Verifica se existe alguma instância de Avaliacao_Model_ParecerDescritivoGeral * persistida para o aluno. * @return bool */ protected function _hasParecerGeral() { if (0 == count($this->getPareceresGerais())) { return FALSE; } return TRUE; } /** * Verifica se existe alguma instância de Avaliacao_Model_ParecerDescritivoAbstract * persistida em uma determinada etapa e retorna o field identity. * * @param Avaliacao_Model_ParecerDescritivoAbstract $instance * @return int|NULL */ protected function _getParecerIdEtapa(Avaliacao_Model_ParecerDescritivoAbstract $instance) { $gerais = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_GERAL ); $componentes = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_COMPONENTE, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_COMPONENTE ); $parecerDescritivo = $this->getRegra()->get('parecerDescritivo'); if (in_array($parecerDescritivo, $gerais)) { if (!$this->_hasParecerGeral()) { return NULL; } $pareceres = $this->getPareceresGerais(); } elseif (in_array($parecerDescritivo, $componentes)) { if (!$this->_hasParecerComponente($instance->get('componenteCurricular'))) { return NULL; } $pareceres = $this->getPareceresComponentes(); $pareceres = $pareceres[$instance->get('componenteCurricular')]; } foreach ($pareceres as $parecer) { if ($instance->etapa == $parecer->etapa) { return $parecer->id; } } } /** * Adiciona notas no boletim. * @param Avaliacao_Model_NotaComponente $nota * @return Avaliacao_Service_Boletim Provê interface fluída */ public function addNota(Avaliacao_Model_NotaComponente $nota) { $key = 'n_' . spl_object_hash($nota); $nota = $this->_addValidators($nota); $nota = $this->_updateEtapa($nota); $nota->notaArredondada = $this->arredondaNota($nota); $this->_notas[$key] = $nota; return $this; } /** * Getter. * @return array */ public function getNotas() { return $this->_notas; } /** * Adiciona um array de instâncias Avaliacao_Model_FaltaAbstract no boletim. * * @param array $faltas * @return Avaliacao_Service_Boletim Provê interface fluída */ public function addFaltas(array $faltas) { foreach ($faltas as $falta) { $this->addFalta($falta); } return $this; } /** * Adiciona faltas no boletim. * @param Avaliacao_Model_FaltaAbstract $falta * @return Avaliacao_Service_Boletim Provê interface fluída */ public function addFalta(Avaliacao_Model_FaltaAbstract $falta) { $key = 'f_' . spl_object_hash($falta); $falta = $this->_addValidators($falta); $falta = $this->_updateEtapa($falta); $this->_faltas[$key] = $falta; return $this; } /** * Getter. * @return array */ public function getFaltas() { return $this->_faltas; } /** * Adiciona uma array de instâncias de Avaliacao_Model_ParecerDescritivoAbstract * no boletim. * * @param array $pareceres * @return Avaliacao_Service_Boletim Provê interface fluída */ public function addPareceres(array $pareceres) { foreach ($pareceres as $parecer) { $this->addParecer($parecer); } return $this; } /** * Adiciona uma instância de Avaliacao_Model_ParecerDescritivoAbstract no * boletim. * * @param Avaliacao_Model_ParecerDescritivoAbstract $parecer * @return Avaliacao_Service_Boletim Provê interface fluída */ public function addParecer(Avaliacao_Model_ParecerDescritivoAbstract $parecer) { $key = 'p_' . spl_object_hash($parecer); $this->_pareceres[$key] = $parecer; $this->_updateParecerEtapa($parecer); $this->_addParecerValidators($parecer); return $this; } /** * Getter para as instâncias de Avaliacao_Model_ParecerDescritivoAbstract * adicionadas no boletim (não persistidas). * * @return array */ public function getPareceres() { return $this->_pareceres; } /** * Atualiza as opções de validação de uma instância de * CoreExt_Validate_Validatable, com os valores permitidos para os atributos * 'componenteCurricular' e 'etapa'. * * @param CoreExt_Validate_Validatable $nota * @return CoreExt_Validate_Validatable * @todo Substituir variável estática por uma de instância {@see _updateParecerEtapa()} */ protected function _addValidators(CoreExt_Validate_Validatable $validatable) { $validators = array(); // Como os componentes serão os mesmos, fazemos cache do validador if (is_null($this->_validators)) { $componentes = $this->getComponentes(); $componentes = CoreExt_Entity::entityFilterAttr($componentes, 'id', 'id'); // Só pode adicionar uma nota/falta para os componentes cursados $validators['componenteCurricular'] = new CoreExt_Validate_Choice( array('choices' => $componentes )); // Pode informar uma nota para as etapas $etapas = $this->getOption('etapas'); $etapas = array_merge(range(1, $etapas, 1), array('Rc')); $validators['etapa'] = new CoreExt_Validate_Choice( array('choices' => $etapas )); $this->_validators = $validators; } $validators = $this->_validators; if ($this->getRegra()->get('tipoPresenca') == RegraAvaliacao_Model_TipoPresenca::POR_COMPONENTE) { $validatable->setValidator('componenteCurricular', $validators['componenteCurricular']); } $validatable->setValidator('etapa', $validators['etapa']); return $validatable; } /** * Atualiza as opções de validação de uma instância de * Avaliacao_Model_ParecerDescritivoAbstract, com os valores permitidos * para os atributos 'componenteCurricular' e 'etapa'. * * @param Avaliacao_Model_ParecerDescritivoAbstract $instance * @return Avaliacao_Model_ParecerDescritivoAbstract */ protected function _addParecerValidators(Avaliacao_Model_ParecerDescritivoAbstract $instance) { if (is_null($this->_parecerValidators)) { $validators = array(); $anuais = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_COMPONENTE ); $etapas = array( RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_COMPONENTE ); $parecerDescritivo = $this->getRegra()->get('parecerDescritivo'); if (in_array($parecerDescritivo, $anuais)) { $validators['etapa'] = new CoreExt_Validate_Choice(array( 'choices' => array('An') )); } elseif (in_array($parecerDescritivo, $etapas)) { $etapas = $this->getOption('etapas'); $etapas = array_merge(range(1, $etapas, 1), array('Rc')); $validators['etapa'] = new CoreExt_Validate_Choice(array( 'choices' => $etapas )); } if ($instance instanceof Avaliacao_Model_ParecerDescritivoComponente) { $componentes = $this->getComponentes(); $componentes = CoreExt_Entity::entityFilterAttr($componentes, 'id', 'id'); $validators['componenteCurricular'] = new CoreExt_Validate_Choice(array( 'choices' => $componentes )); } // Armazena os validadores na instância $this->_parecerValidators = $validators; } $validators = $this->_parecerValidators; // Etapas $instance->setValidator('etapa', $validators['etapa']); // Componentes curriculares if ($instance instanceof Avaliacao_Model_ParecerDescritivoComponente) { $instance->setValidator('componenteCurricular', $validators['componenteCurricular']); } return $instance; } /** * Atualiza a etapa de uma instância de Avaliacao_Model_Etapa. * * @param Avaliacao_Model_Etapa $nota * @return Avaliacao_Model_Etapa */ protected function _updateEtapa(Avaliacao_Model_Etapa $instance) { if (!is_null($instance->etapa) && $instance->isValid('etapa')) { return $instance; } $proximaEtapa = 1; // Se for falta e do tipo geral, verifica qual foi a última etapa if ($instance instanceof Avaliacao_Model_FaltaGeral) { if (0 < count($this->_faltasGerais)) { $etapas = CoreExt_Entity::entityFilterAttr($this->_faltasGerais, 'id', 'etapa'); $proximaEtapa = max($etapas) + 1; } } // Se for nota ou falta por componente, verifica no conjunto qual a última etapa else { if ($instance instanceof Avaliacao_Model_NotaComponente) { $search = '_notasComponentes'; } elseif ($instance instanceof Avaliacao_Model_FaltaComponente) { $search = '_faltasComponentes'; } if (isset($this->{$search}[$instance->get('componenteCurricular')])) { $etapas = CoreExt_Entity::entityFilterAttr( $this->{$search}[$instance->get('componenteCurricular')], 'id', 'etapa' ); $proximaEtapa = max($etapas) + 1; } } // Se ainda estiver dentro dos limites, ok if ($proximaEtapa <= $this->getOption('etapas')) { $instance->etapa = $proximaEtapa; } // Se for maior, verifica se tem recuperação e atribui etapa como 'Rc' elseif ($proximaEtapa > $this->getOption('etapas') && $this->hasRecuperacao()) { $instance->etapa = 'Rc'; } return $instance; } /** * Atualiza a etapa de uma instância de Avaliacao_Model_ParecerDescritivoAbstract * para a última etapa possível. * * @param Avaliacao_Model_ParecerDescritivoAbstract $instance * @return Avaliacao_Model_ParecerDescritivoAbstract */ protected function _updateParecerEtapa(Avaliacao_Model_ParecerDescritivoAbstract $instance) { if (!is_null($instance->etapa)) { return $instance; } $proximaEtapa = 1; $anuais = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_COMPONENTE ); $etapas = array( RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_COMPONENTE ); $componentes = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_COMPONENTE, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_COMPONENTE ); $gerais = array( RegraAvaliacao_Model_TipoParecerDescritivo::ANUAL_GERAL, RegraAvaliacao_Model_TipoParecerDescritivo::ETAPA_GERAL ); $parecerDescritivo = $this->getRegra()->get('parecerDescritivo'); if (in_array($parecerDescritivo, $anuais)) { $instance->etapa = 'An'; return $instance; } elseif (in_array($parecerDescritivo, $etapas)) { $attrValues = array(); if (in_array($parecerDescritivo, $gerais)) { $attrValues = $this->getPareceresGerais(); } elseif (in_array($parecerDescritivo, $componentes)) { $pareceresComponentes = $this->getPareceresComponentes(); if (isset($pareceresComponentes[$instance->get('componenteCurricular')])) { $attrValues = $pareceresComponentes[$instance->get('componenteCurricular')]; } } if (0 < count($attrValues)) { $etapas = CoreExt_Entity::entityFilterAttr($attrValues, 'id', 'etapa'); $proximaEtapa = max($etapas) + 1; } } if ($proximaEtapa <= $this->getOption('etapas')) { $instance->etapa = $proximaEtapa; } elseif ($this->hasRecuperacao()) { $instance->etapa = 'Rc'; } return $instance; } /** * Arredonda uma nota através da tabela de arredondamento da regra de avaliação. * @param Avaliacao_Model_NotaComponente|int $nota * @return mixed * @throws CoreExt_Exception_InvalidArgumentException */ public function arredondaNota($nota) { if ($nota instanceof Avaliacao_Model_NotaComponente) { $nota = $nota->nota; } if (!is_numeric($nota)) { require_once 'CoreExt/Exception/InvalidArgumentException.php'; throw new CoreExt_Exception_InvalidArgumentException(sprintf( 'O parâmetro $nota ("%s") não é um valor numérico.', $nota )); } return $this->getRegra()->tabelaArredondamento->round($nota); } /** * Prevê a nota necessária para que o aluno seja aprovado após a recuperação * escolar. * * @param int $id * @return TabelaArredondamento_Model_TabelaValor|NULL * @see TabelaArredondamento_Model_Tabela#predictValue() */ public function preverNotaRecuperacao($id) { /* if (is_null($this->getRegra()->formulaRecuperacao) || !isset($this->_notasComponentes[$id])) { return NULL; } $notas = $this->_notasComponentes[$id]; $somaEtapas = array_sum(CoreExt_Entity::entityFilterAttr($notas, 'etapa', 'nota')); $formula = $this->getRegra()->formulaRecuperacao; $data = array( 'formulaValues' => array( 'Se' => $somaEtapas, 'Et' => $this->getOption('etapas'), 'Rc' => NULL ), 'expected' => array( 'var' => 'Rc', 'value' => $this->getRegra()->media ) ); foreach ($notas as $nota) { $data['formulaValues']['E' . $nota->etapa] = $nota->nota; } return $this->getRegra()->tabelaArredondamento->predictValue($formula, $data); */ if (is_null($this->getRegra()->formulaRecuperacao) || !isset($this->_notasComponentes[$id])) { return NULL; } $notas = $this->_notasComponentes[$id]; unset($notas[$this->getOption('etapas')]); $somaEtapas = array_sum(CoreExt_Entity::entityFilterAttr($notas, 'etapa', 'nota')); $formula = $this->getRegra()->formulaRecuperacao; $data = array( 'Se' => $somaEtapas, 'Et' => $this->getOption('etapas'), 'Rc' => NULL ); foreach ($notas as $nota) { $data['E' . $nota->etapa] = $nota->nota; } for($i = 0.1 ; $i<=10; $i+=0.1){ $data['Rc']=$i; if ($this->getRegra()->formulaRecuperacao->execFormulaMedia($data) >= $this->getRegra()->mediaRecuperacao) return $i; } return null; } /** * @param numeric $falta * @param numeric $horaFalta * @return numeric */ protected function _calculateHoraFalta($falta, $horaFalta) { return ($falta * $horaFalta); } /** * Calcula a proporção de $num2 para $num1. * * @param numeric $num1 * @param numeric $num2 * @param bool $decimal Opcional. Se o resultado é retornado como decimal * ou percentual. O padrão é TRUE. * @return float */ protected function _calculatePorcentagem($num1, $num2, $decimal = TRUE) { $num1 = floatval($num1); $num2 = floatval($num2); if ($num1 == 0) { return 0; } $perc = $num2 / $num1; return ($decimal == TRUE ? $perc : ($perc * 100)); } /** * Calcula uma média de acordo com uma fórmula de FormulaMedia_Model_Media * da regra de avaliação da série/matrícula do aluno. * * @param array $values * @return float */ protected function _calculaMedia(array $values) { if (isset($values['Rc']) && $this->hasRecuperacao()) { $media = $this->getRegra()->formulaRecuperacao->execFormulaMedia($values); } else { $media = $this->getRegra()->formulaMedia->execFormulaMedia($values); } return $media; } /** * Insere ou atualiza as notas e/ou faltas que foram adicionadas ao service * e atualiza a matricula do aluno de acordo com a sua performance, * promovendo-o ou retendo-o caso o tipo de progressão da regra de avaliação * seja automática (e que a situação do aluno não esteja em "andamento"). * * @see Avaliacao_Service_Boletim#getSituacaoAluno() * @throws CoreExt_Service_Exception|Exception */ public function save() { try { $this->saveNotas() ->saveFaltas() ->savePareceres() ->promover(); } catch (CoreExt_Service_Exception $e) { throw $e; } catch (Exception $e) { throw $e; } } /** * Insere ou atualiza as notas no boletim do aluno. * @return Avaliacao_Service_Boletim Provê interface fluída */ public function saveNotas() { if ($this->getRegra()->get('tipoNota') == RegraAvaliacao_Model_Nota_TipoValor::NENHUM) { return $this; } $notaAluno = $this->_getNotaAluno(); $notas = $this->getNotas(); foreach ($notas as $nota) { $nota->notaAluno = $notaAluno; $nota->id = $this->_getNotaIdEtapa($nota); $this->getNotaComponenteDataMapper()->save($nota); } // Atualiza as médias $this->_updateNotaComponenteMedia(); return $this; } /** * Insere ou atualiza as faltas no boletim. * @return Avaliacao_Service_Boletim Provê interface fluída */ public function saveFaltas() { $faltaAluno = $this->_getFaltaAluno(); $faltas = $this->getFaltas(); foreach ($faltas as $falta) { $falta->faltaAluno = $faltaAluno; $falta->id = $this->_getFaltaIdEtapa($falta); $this->getFaltaAbstractDataMapper()->save($falta); } return $this; } /** * Insere ou atualiza os pareceres no boletim. * @return Avaliacao_Service_Boletim Provê interface fluída */ public function savePareceres() { $parecerAluno = $this->_getParecerDescritivoAluno(); $pareceres = $this->getPareceres(); foreach ($pareceres as $parecer) { $parecer->parecerDescritivoAluno = $parecerAluno->id; $parecer->id = $this->_getParecerIdEtapa($parecer); $this->getParecerDescritivoAbstractDataMapper()->save($parecer); } return $this; } protected function updateSituacaoMatricula($situacaoNotasFaltas) { $matriculaSituacao = null; //se a situacao da matricula não é aprovado e a situacao da nota e falta estão aprovadas, aprova a matricula if (($this->getOption('aprovado') != App_Model_MatriculaSituacao::APROVADO) && ($situacaoNotasFaltas->aprovado && ! $situacaoNotasFaltas->andamento)) { $matriculaSituacao = App_Model_MatriculaSituacao::APROVADO; } //se a situacao da matricula não é reprovado e a situacao da nota e falta não estão aprovadas e nem em andamento, reprova a matricula elseif (($this->getOption('aprovado') != App_Model_MatriculaSituacao::REPROVADO) && (! $situacaoNotasFaltas->aprovado && ! $situacaoNotasFaltas->andamento)) { $matriculaSituacao = App_Model_MatriculaSituacao::REPROVADO; } elseif ($this->getOption('aprovado') != App_Model_MatriculaSituacao::EM_ANDAMENTO) { $matriculaSituacao = App_Model_MatriculaSituacao::EM_ANDAMENTO; } if ($matriculaSituacao) $this->_updateMatricula($this->getOption('matricula'), $this->getOption('usuario'), $matriculaSituacao); } /** * Promove o aluno de etapa escolar caso esteja aprovado de acordo com o * necessário estabelecido por tipoProgressao de * RegraAvaliacao_Model_Regra. * * @param bool $ok Caso a progressão não seja automática, é necessário uma * confirmação externa para a promoção do aluno. * @return bool */ public function promover($novaSituacaoMatricula = NULL) { $tipoProgressao = $this->getRegra()->get('tipoProgressao'); $situacaoMatricula = $this->getOption('aprovado'); $situacaoBoletim = $this->getSituacaoAluno(); $exceptionMsg = ''; if ($situacaoBoletim->andamento) $novaSituacaoMatricula = App_Model_MatriculaSituacao::EM_ANDAMENTO; else { switch ($tipoProgressao) { case RegraAvaliacao_Model_TipoProgressao::CONTINUADA: $novaSituacaoMatricula = App_Model_MatriculaSituacao::APROVADO; break; case RegraAvaliacao_Model_TipoProgressao::NAO_CONTINUADA_AUTO_MEDIA_PRESENCA: if ($situacaoBoletim->aprovado && !$situacaoBoletim->retidoFalta) $novaSituacaoMatricula = App_Model_MatriculaSituacao::APROVADO; else $novaSituacaoMatricula = App_Model_MatriculaSituacao::REPROVADO; break; case RegraAvaliacao_Model_TipoProgressao::NAO_CONTINUADA_AUTO_SOMENTE_MEDIA: if ($situacaoBoletim->aprovado) $novaSituacaoMatricula = App_Model_MatriculaSituacao::APROVADO; else $novaSituacaoMatricula = App_Model_MatriculaSituacao::REPROVADO; break; case RegraAvaliacao_Model_TipoProgressao::NAO_CONTINUADA_MANUAL && is_null($novaSituacaoMatricula): $tipoProgressaoInstance = RegraAvaliacao_Model_TipoProgressao::getInstance(); $exceptionMsg = sprintf('Para atualizar a matrícula em uma regra %s é ' . 'necessário passar o valor do argumento "$novaSituacaoMatricula".', $tipoProgressaoInstance->getValue($tipoProgressao)); break; } } if($novaSituacaoMatricula == $situacaoMatricula) $exceptionMsg = "Matrícula ({$this->getOption('matricula')}) não precisou ser promovida, " . "pois a nova situação continua a mesma da anterior ($novaSituacaoMatricula)"; if ($exceptionMsg) { require_once 'CoreExt/Service/Exception.php'; throw new CoreExt_Service_Exception($exceptionMsg); } return $this->_updateMatricula($this->getOption('matricula'), $this->getOption('usuario'), $novaSituacaoMatricula); } /** * Atualiza a média dos componentes curriculares. */ protected function _updateNotaComponenteMedia() { require_once 'Avaliacao/Model/NotaComponenteMedia.php'; $this->_loadNotaComponenteCurricular(FALSE); foreach ($this->_notasComponentes as $id => $notasComponentes) { // Cria um array onde o índice é a etapa $etapasNotas = CoreExt_Entity::entityFilterAttr($notasComponentes, 'etapa', 'nota'); $notas = array('Se' => 0, 'Et' => $this->getOption('etapas')); // Cria o array formatado para o cálculo da fórmula da média foreach ($etapasNotas as $etapa => $nota) { if (is_numeric($etapa)) { $notas['E' . $etapa] = $nota; $notas['Se'] += $nota; continue; } $notas[$etapa] = $nota; } // Calcula a média $media = $this->_calculaMedia($notas); // Cria uma nova instância de média, já com a nota arredondada e a etapa $notaComponenteCurricularMedia = new Avaliacao_Model_NotaComponenteMedia(array( 'notaAluno' => $this->_getNotaAluno()->id, 'componenteCurricular' => $id, 'media' => $media, 'mediaArredondada' => $this->arredondaNota($media), 'etapa' => $etapa )); try { // Se existir, marca como "old" para possibilitar a atualização $this->getNotaComponenteMediaDataMapper()->find(array( $notaComponenteCurricularMedia->get('notaAluno'), $notaComponenteCurricularMedia->get('componenteCurricular'), )); $notaComponenteCurricularMedia->markOld(); } catch (Exception $e) { // Prossegue, sem problemas. } // Salva a média $this->getNotaComponenteMediaDataMapper()->save($notaComponenteCurricularMedia); } } /** * Atualiza os dados da matrícula do aluno. * * @param int $matricula * @param int $usuario * @param bool $promover * @return bool * @see App_Model_Matricula#atualizaMatricula($matricula, $usuario, $promover) */ protected function _updateMatricula($matricula, $usuario, $promover) { return App_Model_Matricula::atualizaMatricula($matricula, $usuario, $promover); } public function deleteNota($etapa, $ComponenteCurricularId) { // zera nota antes de deletar, para que a media seja recalculada try { $nota = new Avaliacao_Model_NotaComponente(array( 'componenteCurricular' => $ComponenteCurricularId, 'nota' => 0, 'etapa' => $etapa )); $this->addNota($nota); $this->save(); } catch (Exception $e) { error_log("Excessao ignorada ao zerar nota a ser removida: " . $e->getMessage()); } $nota = $this->getNotaComponente($ComponenteCurricularId, $etapa); $this->getNotaComponenteDataMapper()->delete($nota); return $this; } public function deleteFalta($etapa, $ComponenteCurricularId) { $nota = $this->getFalta($etapa, $ComponenteCurricularId); $this->getFaltaAbstractDataMapper()->delete($nota); return $this; } public function deleteParecer($etapa, $ComponenteCurricularId) { $parecer = $this->getParecerDescritivo($etapa, $ComponenteCurricularId); $this->getParecerDescritivoAbstractDataMapper()->delete($parecer); return $this; } }