Gestión de documentos de candidato
git-svn-id: https://192.168.0.254/svn/Proyectos.Incam_IntranetNueva/trunk@62 77cfc57b-8ef4-1849-9df6-4a38aa5da120
This commit is contained in:
parent
471f9f24da
commit
d3abfa60af
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
@ -4,8 +4,8 @@
|
||||
$yiiPath = dirname(__FILE__) . '/../../../yii/framework/yii.php';
|
||||
|
||||
// Set YII_DEBUG and YII_TRACE_LEVEL flags
|
||||
$debug = true;
|
||||
$traceLevel = 0;
|
||||
//$debug = true;
|
||||
//$traceLevel = 0;
|
||||
|
||||
$config = array(
|
||||
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
|
||||
@ -23,7 +23,6 @@ $config = array(
|
||||
'ext.PageSize.*',
|
||||
'application.modules.auditTrail.models.AuditTrail',
|
||||
),
|
||||
|
||||
|
||||
'modules'=>array(
|
||||
'auditTrail'=>array(
|
||||
|
||||
@ -59,9 +59,12 @@ $configSpecific = array(
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
|
||||
'params'=>array(
|
||||
// Ruta de los currículums de los candidatos
|
||||
'curriculumPath' => dirname(__FILE__) . '/../../documentos/',
|
||||
),
|
||||
);
|
||||
|
||||
?>
|
||||
263
www/protected/controllers/CandidatoDocumentoController.php
Normal file
263
www/protected/controllers/CandidatoDocumentoController.php
Normal file
@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
Yii::import('application.helpers.FileHelper');
|
||||
Yii::import('application.helpers.GDownloadHelper');
|
||||
|
||||
class CandidatoDocumentoController extends Controller {
|
||||
|
||||
/**
|
||||
* @var string the default layout for the views. Defaults to '//layouts/column2', meaning
|
||||
* using two-column layout. See 'protected/views/layouts/column2.php'.
|
||||
*/
|
||||
public $layout = '//layouts/default';
|
||||
|
||||
/**
|
||||
* @return array action filters
|
||||
*/
|
||||
public function filters() {
|
||||
return array(
|
||||
'accessControl', // perform access control for CRUD operations
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the access control rules.
|
||||
* This method is used by the 'accessControl' filter.
|
||||
* @return array access control rules
|
||||
*/
|
||||
public function accessRules() {
|
||||
return array(
|
||||
array('allow', // allow authenticated user to perform 'create' and 'update' actions
|
||||
'actions' => array('index', 'view', 'create', 'update', 'delete', 'admin', 'upload'),
|
||||
'users' => array('@'),
|
||||
),
|
||||
array('allow', // deny all users
|
||||
'users' => array('*'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a particular model.
|
||||
* @param integer $id the ID of the model to be displayed
|
||||
*/
|
||||
public function actionView($id) {
|
||||
$this->render('view', array(
|
||||
'model' => $this->loadModel($id),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Guarda el documento en el sistema
|
||||
* @param CandidatoDocumento $documento el documento
|
||||
* @param CUploadedFile $file el fichero asociado al documento a guardar
|
||||
* @return boolean true cuando el fichero se guarda correctamente
|
||||
*/
|
||||
private function guardarDocumento($documento, $file) {
|
||||
if (!is_null($file)) {
|
||||
$folder = $this->darRutaDocumentos() . $documento->candidato_id . '/';
|
||||
|
||||
if (!is_dir($folder))
|
||||
mkdir($folder, 0755, true);
|
||||
|
||||
$file->saveAs($folder . $documento->nombre_fichero);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera un nombre de fichero para guardar el documento. Se comprueba
|
||||
* que no exista ningún otro fichero con ese mismo nombre.
|
||||
* @param CandidatoDocumento $model Documento
|
||||
* @return string
|
||||
*/
|
||||
private function generarNombreDocumento($model) {
|
||||
$cid = $model->candidato_id;
|
||||
$old_filename = FileHelper::sanitizeFileName(pathinfo($model->nombre_fichero, PATHINFO_FILENAME));
|
||||
$ext = pathinfo($model->nombre_fichero, PATHINFO_EXTENSION);
|
||||
$folder = $this->darRutaDocumentos() . $cid . '/';
|
||||
$contador = 1;
|
||||
|
||||
$filename = $old_filename . '.' . $ext;
|
||||
|
||||
// existe el directorio?
|
||||
if (is_dir($folder)) {
|
||||
// ya existe el fichero?
|
||||
while (file_exists($folder . $filename)) {
|
||||
$filename = $old_filename . '_' . $contador . '.' . $ext;
|
||||
$contador++;
|
||||
}
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Da la ruta donde se guardan los documentos
|
||||
* @return string ruta de los documentos
|
||||
*/
|
||||
private function darRutaDocumentos() {
|
||||
return Yii::app()->params['curriculumPath'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Borrar el documento del sistema
|
||||
* @param CandidatoDocumento $documento el documento a borrar
|
||||
* @return boolean true cuando el fichero se borra correctamente
|
||||
*/
|
||||
private function borrarDocumento($documento) {
|
||||
$cid = $documento->candidato_id;
|
||||
$folder = $this->darRutaDocumentos() . $cid . '/';
|
||||
|
||||
if (file_exists($folder . $documento->nombre_fichero))
|
||||
unlink($folder . $documento->nombre_fichero);
|
||||
}
|
||||
|
||||
/**
|
||||
* Descarga el documento
|
||||
* @param integer $id el ID del documento
|
||||
*/
|
||||
public function actionDownload($id) {
|
||||
$model = $this->loadModel($id);
|
||||
$cid = $model->candidato_id;
|
||||
$folder = $this->darRutaDocumentos() . $model->candidato_id . '/' . $model->nombre_fichero;
|
||||
|
||||
GDownloadHelper::send($folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new model.
|
||||
* @param integer $cid el ID del candidato
|
||||
*/
|
||||
public function actionCreate($cid) {
|
||||
$model = new CandidatoDocumento;
|
||||
$model->candidato_id = $cid;
|
||||
|
||||
$candidato = Candidato::model()->findByPk($cid);
|
||||
|
||||
// Uncomment the following line if AJAX validation is needed
|
||||
// $this->performAjaxValidation($model);
|
||||
|
||||
if (isset($_POST['CandidatoDocumento'])) {
|
||||
$model->attributes = $_POST['CandidatoDocumento'];
|
||||
$documento = CUploadedFile::getInstance($model, 'file');
|
||||
$model->nombre_fichero = $documento->name;
|
||||
|
||||
// Me aseguro que el nombre del fichero no tiene "cosas raras"
|
||||
$model->nombre_fichero = $this->generarNombreDocumento($model);
|
||||
|
||||
if ($model->save()) {
|
||||
$this->guardarDocumento($model, $documento);
|
||||
Yii::app()->user->setFlash('success', Yii::t('intranet', 'Currículum guardado correctamente.'));
|
||||
$url = $this->createUrl('index', array('cid' => $model->candidato_id));
|
||||
$this->redirect($url);
|
||||
}
|
||||
}
|
||||
|
||||
$this->render('create', array(
|
||||
'model' => $model,
|
||||
'candidato' => $candidato,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a particular model.
|
||||
* If update is successful, the browser will be redirected to the 'view' page.
|
||||
* @param integer $id the ID of the model to be updated
|
||||
*/
|
||||
public function actionUpdate($id) {
|
||||
$model = $this->loadModel($id);
|
||||
|
||||
// Uncomment the following line if AJAX validation is needed
|
||||
// $this->performAjaxValidation($model);
|
||||
|
||||
if (isset($_POST['CandidatoDocumento'])) {
|
||||
$model->attributes = $_POST['CandidatoDocumento'];
|
||||
if ($model->save())
|
||||
$this->redirect(array('view', 'id' => $model->id));
|
||||
}
|
||||
|
||||
$this->render('update', array(
|
||||
'model' => $model,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a particular model.
|
||||
* If deletion is successful, the browser will be redirected to the 'admin' page.
|
||||
* @param integer $id the ID of the model to be deleted
|
||||
*/
|
||||
public function actionDelete($id) {
|
||||
if (Yii::app()->request->isPostRequest) {
|
||||
// we only allow deletion via POST request
|
||||
|
||||
$model = $this->loadModel($id);
|
||||
|
||||
if ($model->delete()) {
|
||||
$this->borrarDocumento($model);
|
||||
}
|
||||
|
||||
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
|
||||
if (!isset($_GET['ajax']))
|
||||
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
|
||||
}
|
||||
else
|
||||
throw new CHttpException(400, 'Invalid request. Please do not repeat this request again.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all models.
|
||||
*/
|
||||
public function actionIndex($cid) {
|
||||
$this->layout = '//layouts/candidato';
|
||||
$candidato = Candidato::model()->findByPk($cid);
|
||||
|
||||
$dataProvider = new CActiveDataProvider('CandidatoDocumento', array(
|
||||
'criteria' => array(
|
||||
'condition' => 'candidato_id=' . $cid,
|
||||
),
|
||||
));
|
||||
|
||||
$this->render('index', array(
|
||||
'dataProvider' => $dataProvider,
|
||||
'candidato' => $candidato,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages all models.
|
||||
*/
|
||||
public function actionAdmin() {
|
||||
$model = new CandidatoDocumento('search');
|
||||
$model->unsetAttributes(); // clear any default values
|
||||
if (isset($_GET['CandidatoDocumento']))
|
||||
$model->attributes = $_GET['CandidatoDocumento'];
|
||||
|
||||
$this->render('admin', array(
|
||||
'model' => $model,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data model based on the primary key given in the GET variable.
|
||||
* If the data model is not found, an HTTP exception will be raised.
|
||||
* @param integer the ID of the model to be loaded
|
||||
*/
|
||||
public function loadModel($id) {
|
||||
$model = CandidatoDocumento::model()->findByPk($id);
|
||||
if ($model === null)
|
||||
throw new CHttpException(404, 'The requested page does not exist.');
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the AJAX validation.
|
||||
* @param CModel the model to be validated
|
||||
*/
|
||||
protected function performAjaxValidation($model) {
|
||||
if (isset($_POST['ajax']) && $_POST['ajax'] === 'candidato-documento-form') {
|
||||
echo CActiveForm::validate($model);
|
||||
Yii::app()->end();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
46
www/protected/helpers/FileHelper.php
Normal file
46
www/protected/helpers/FileHelper.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* FileHelper holds a collection of static methods, useful for generic purposes
|
||||
*
|
||||
*/
|
||||
class FileHelper {
|
||||
|
||||
/**
|
||||
* Returns a safe filename by replacing all dangerous characters
|
||||
* with an underscore.
|
||||
*
|
||||
* @param string $filename The source filename to be "sanitized"
|
||||
*
|
||||
* @return Boolean string A safe version of the input filename
|
||||
*/
|
||||
public static function sanitizeFileName($filename) {
|
||||
// replace non letter or digits by -
|
||||
$filename = preg_replace('#[^\\pL\d]+#u', '-', $filename);
|
||||
|
||||
// trim
|
||||
$filename = trim($filename, '-');
|
||||
|
||||
// transliterate
|
||||
if (function_exists('iconv')) {
|
||||
$filename = iconv('utf-8', 'us-ascii//TRANSLIT', $filename);
|
||||
}
|
||||
|
||||
// lowercase
|
||||
$filename = strtolower($filename);
|
||||
|
||||
// remove unwanted characters
|
||||
$filename = preg_replace('#[^-\w]+#', '', $filename);
|
||||
|
||||
if (empty($filename)) {
|
||||
return 'n-a';
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// usage:
|
||||
//$safe_filename = FileHelper::sanitizeFileName('#my unsaf&/file\name?"');
|
||||
?>;
|
||||
200
www/protected/helpers/GDownloadHelper.php
Normal file
200
www/protected/helpers/GDownloadHelper.php
Normal file
@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Rasmus Schultz
|
||||
* @link http://mindplay.dk
|
||||
* @copyright Copyright © 2010 Rasmus Schultz
|
||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class allows multi-threaded file downloads, and regular file downloads.
|
||||
*
|
||||
* You can use this class when you need to control which users are allowed to
|
||||
* download a file from a protected area of the local filesystem.
|
||||
*
|
||||
* Note that downloading files in this way does result in some memory and processor
|
||||
* overhead - you should not use this class sporadically for all downloads in your
|
||||
* application, only when a regular download is not possible for some reason (usually
|
||||
* because the file in question must not be made available to the general public).
|
||||
*
|
||||
* Avoid using this class when you need to log access to a public file - you're
|
||||
* probably better off using a pre-download logging action, which then redirects to
|
||||
* the actual file download.
|
||||
*/
|
||||
class GDownloadHelper {
|
||||
|
||||
/**
|
||||
* Buffer size (memory requirement per download / user / thread)
|
||||
*/
|
||||
const BUFFER_SIZE = 32768; # = 1024*32
|
||||
|
||||
/**
|
||||
* Time limit (time allowed to send one buffer)
|
||||
*/
|
||||
const TIME_LIMIT = 30;
|
||||
|
||||
/**
|
||||
* Sends a file to the client.
|
||||
*
|
||||
* This is a blocking method, which means that the method-call will not return until
|
||||
* the client has completed the download of the file (or segment), or until the client
|
||||
* is disconnected and the connection/download is aborted.
|
||||
*
|
||||
* Check the return value of this method to see if the download was successful - this
|
||||
* if useful, for example, if you need to count and limit the number of times a user can
|
||||
* download a file; you should increase your counters only if the call returns TRUE.
|
||||
*
|
||||
* It is important that your action produces <strong>no other output</strong> before
|
||||
* or after calling this method, as this will corrupt the downloaded binary file.
|
||||
*
|
||||
* Output buffers will be cleared and disabled, and any active CWebLogRoute instances
|
||||
* (which might otherwise output logging information at the end of the request) will
|
||||
* be detected and disabled.
|
||||
*
|
||||
* If your application might produce any other output after your action completes, you
|
||||
* should suppress this by using the exit statement at the end of your action.
|
||||
*
|
||||
* This method throws a CException if the specified path does not point to a valid file.
|
||||
*
|
||||
* This method throws a CHttpException (416) if the requested range is invalid.
|
||||
*
|
||||
* @param string full path to a file on the local filesystem being sent to the client.
|
||||
* @param string optional, alternative filename as the client will see it (defaults to the local filename specified in $path)
|
||||
* @return boolean true if the download succeeded, false if the connection was aborted prematurely.
|
||||
*/
|
||||
public static function send($path, $name=null)
|
||||
{
|
||||
// turn off output buffering
|
||||
while (ob_get_level())
|
||||
ob_end_clean();
|
||||
|
||||
// disable any CWebLogRoutes to prevent them from outputting at the end of the request
|
||||
foreach (Yii::app()->log->routes as $route)
|
||||
if ($route instanceof CWebLogRoute)
|
||||
$route->enabled = false;
|
||||
|
||||
// obtain headers:
|
||||
$envs = '';
|
||||
foreach ($_ENV as $item => $value)
|
||||
if (substr($item, 0, 5) == 'HTTP_')
|
||||
$envs .= $item.' => '.$value."\n";
|
||||
if (function_exists('apache_request_headers')) {
|
||||
$headers = apache_request_headers();
|
||||
foreach ($headers as $header => $value) {
|
||||
$envs .= "apache: $header = $value\n";
|
||||
}
|
||||
}
|
||||
|
||||
// obtain filename, if needed:
|
||||
if (is_null($name))
|
||||
$name = basename($path);
|
||||
|
||||
// verify path and connection status:
|
||||
if (!is_file($path) || !is_readable($path) || connection_status()!=0)
|
||||
throw new CException('GDownload::send() : unable to access local file "'.$path.'"');
|
||||
|
||||
// obtain filesize:
|
||||
$size = filesize($path);
|
||||
|
||||
// configure download range for multi-threaded / resumed downloads:
|
||||
if (isset($_ENV['HTTP_RANGE']))
|
||||
{
|
||||
list($a, $range) = explode("=", $_ENV['HTTP_RANGE']);
|
||||
}
|
||||
else if (function_exists('apache_request_headers'))
|
||||
{
|
||||
$headers = apache_request_headers();
|
||||
if (isset($headers['Range'])) {
|
||||
list($a, $range) = explode("=", $headers['Range']);
|
||||
} else {
|
||||
$range = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$range = false;
|
||||
}
|
||||
|
||||
// produce required headers for partial downloads:
|
||||
if ($range)
|
||||
{
|
||||
header('HTTP/1.1 206 Partial content');
|
||||
list($begin, $end) = explode("-", $range);
|
||||
if ($begin == '')
|
||||
{
|
||||
$begin = $size-$end;
|
||||
$end = $size-1;
|
||||
}
|
||||
else if ($end == '')
|
||||
{
|
||||
$end = $size-1;
|
||||
}
|
||||
$header = 'Content-Range: bytes '.$begin.'-'.$end.'/'.($size);
|
||||
$size = $end-$begin+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$header = false;
|
||||
$begin = 0;
|
||||
$end = $size-1;
|
||||
}
|
||||
|
||||
// check range:
|
||||
if (($begin > $size-1) || ($end > $size-1) || ($begin > $end))
|
||||
throw new CHttpException(416,'Requested range not satisfiable');
|
||||
|
||||
// suppress client-side caching:
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
|
||||
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
|
||||
|
||||
// send a generic content-type:
|
||||
header("Content-Type: application/octet-stream");
|
||||
|
||||
// send content-range header, if present:
|
||||
if ($header) header($header);
|
||||
|
||||
// send content-length header:
|
||||
header("Content-Length: ".$size);
|
||||
|
||||
// send content-disposition, with special handling for IE:
|
||||
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE)
|
||||
{
|
||||
header("Content-Disposition: inline; filename=".str_replace(' ', '%20', $name));
|
||||
}
|
||||
else
|
||||
{
|
||||
header("Content-Disposition: inline; filename=\"$name\"");
|
||||
}
|
||||
|
||||
// set encoding:
|
||||
header("Content-Transfer-Encoding: binary\n");
|
||||
|
||||
// stream out the binary data:
|
||||
if ($file = fopen($path, 'rb'))
|
||||
{
|
||||
fseek($file, $begin);
|
||||
$sent = 0;
|
||||
while ($sent < $size)
|
||||
{
|
||||
set_time_limit(self::TIME_LIMIT);
|
||||
$bytes = $end - ftell($file) + 1;
|
||||
if ($bytes > self::BUFFER_SIZE)
|
||||
$bytes = self::BUFFER_SIZE;
|
||||
echo fread($file, $bytes);
|
||||
$sent += $bytes;
|
||||
flush();
|
||||
if (connection_aborted())
|
||||
break;
|
||||
}
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
// check connection status and return:
|
||||
$status = (connection_status()==0) and !connection_aborted();
|
||||
return $status;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
class m120504_095056_tbl_candidatos_documentos extends CDbMigration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->createTable('tbl_candidatos_documentos', array(
|
||||
'id' => 'pk',
|
||||
'candidato_id' => 'integer NOT NULL',
|
||||
'fecha' => 'datetime',
|
||||
'tipo' => 'string',
|
||||
'nombre_fichero' => 'string',
|
||||
));
|
||||
$this->addForeignKey('fk_candidatos_documentos_1', 'tbl_candidatos_documentos', 'candidato_id', 'tbl_candidatos', 'id', 'CASCADE', 'CASCADE');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->dropForeignKey('fk_candidatos_documentos_1', 'tbl_candidatos_documentos');
|
||||
$this->dropTable('tbl_candidatos_documentos');
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// Use safeUp/safeDown to do migration with transaction
|
||||
public function safeUp()
|
||||
{
|
||||
}
|
||||
|
||||
public function safeDown()
|
||||
{
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -35,6 +35,7 @@
|
||||
* @property CandidatoCapacidad[] $capacidades
|
||||
* @property CandidatoIdioma[] $idiomas
|
||||
* @property CandidatoTitulacion[] $titulaciones
|
||||
* @property CandidatoDocumento[] $documentos
|
||||
*/
|
||||
class Candidato extends CActiveRecord
|
||||
{
|
||||
@ -204,6 +205,8 @@ class Candidato extends CActiveRecord
|
||||
'idiomasCount' => array(self::STAT, 'CandidatoIdioma', 'candidato_id'),
|
||||
'titulaciones' => array(self::HAS_MANY, 'CandidatoTitulacion', 'candidato_id'),
|
||||
'titulacionesCount' => array(self::STAT, 'CandidatoTitulacion', 'candidato_id'),
|
||||
'documentos' => array(self::HAS_MANY, 'CandidatoDocumento', 'candidato_id'),
|
||||
'documentosCount' => array(self::STAT, 'CandidatoDocumento', 'candidato_id'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
145
www/protected/models/CandidatoDocumento.php
Normal file
145
www/protected/models/CandidatoDocumento.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This is the model class for table "tbl_candidatos_documentos".
|
||||
*
|
||||
* The followings are the available columns in table 'tbl_candidatos_documentos':
|
||||
* @property integer $id
|
||||
* @property integer $candidato_id
|
||||
* @property datetime $fecha
|
||||
* @property string $tipo
|
||||
* @property string $nombre_fichero
|
||||
*
|
||||
* The followings are the available model relations:
|
||||
* @property Candidatos $candidato
|
||||
*/
|
||||
class CandidatoDocumento extends CActiveRecord
|
||||
{
|
||||
public $url;
|
||||
|
||||
const TIPO_INTERNO='Interno';
|
||||
const TIPO_COMERCIAL='Comercial';
|
||||
|
||||
/**
|
||||
* Devuelve la lista de tipos de documento.
|
||||
* @return array lista de tipos
|
||||
*/
|
||||
public function getOpcionesTipo() {
|
||||
return array(
|
||||
self::TIPO_INTERNO => 'Interno',
|
||||
self::TIPO_COMERCIAL => 'Comercial'
|
||||
);
|
||||
}
|
||||
|
||||
public function getReadableFileSize($retstring = null) {
|
||||
// adapted from code at http://aidanlister.com/repos/v/function.size_readable.php
|
||||
$sizes = array('bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
|
||||
|
||||
if ($retstring === null) { $retstring = '%01.2f %s'; }
|
||||
|
||||
$lastsizestring = end($sizes);
|
||||
|
||||
foreach ($sizes as $sizestring) {
|
||||
if ($this->size < 1024) { break; }
|
||||
if ($sizestring != $lastsizestring) { $this->size /= 1024; }
|
||||
}
|
||||
if ($sizestring == $sizes[0]) { $retstring = '%01d %s'; } // Bytes aren't normally fractional
|
||||
return sprintf($retstring, $this->size, $sizestring);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the static model of the specified AR class.
|
||||
* @param string $className active record class name.
|
||||
* @return CandidatoDocumento the static model class
|
||||
*/
|
||||
public static function model($className=__CLASS__)
|
||||
{
|
||||
return parent::model($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the associated database table name
|
||||
*/
|
||||
public function tableName()
|
||||
{
|
||||
return 'tbl_candidatos_documentos';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array validation rules for model attributes.
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
// NOTE: you should only define rules for those attributes that
|
||||
// will receive user inputs.
|
||||
return array(
|
||||
array('candidato_id', 'required'),
|
||||
array('candidato_id', 'numerical', 'integerOnly'=>true),
|
||||
array('tipo, nombre_fichero', 'length', 'max'=>255),
|
||||
array('fecha', 'safe'),
|
||||
|
||||
// The following rule is used by search().
|
||||
// Please remove those attributes that should not be searched.
|
||||
array('id, candidato_id, fecha, tipo, nombre_fichero', 'safe', 'on'=>'search'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
protected function afterConstruct() {
|
||||
// Valores por defecto
|
||||
$this->tipo = self::TIPO_INTERNO;
|
||||
$this->fecha = date('Y-m-d H:i:s', time());
|
||||
parent::afterConstruct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array relational rules.
|
||||
*/
|
||||
public function relations()
|
||||
{
|
||||
// NOTE: you may need to adjust the relation name and the related
|
||||
// class name for the relations automatically generated below.
|
||||
return array(
|
||||
'candidato' => array(self::BELONGS_TO, 'Candidatos', 'candidato_id'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array customized attribute labels (name=>label)
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array(
|
||||
'id' => 'ID',
|
||||
'candidato_id' => 'Candidato',
|
||||
'fecha' => 'Fecha',
|
||||
'tipo' => 'Tipo',
|
||||
'nombre_fichero' => 'Nombre',
|
||||
'file' => 'Fichero',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of models based on the current search/filter conditions.
|
||||
* @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
// Warning: Please modify the following code to remove attributes that
|
||||
// should not be searched.
|
||||
|
||||
$criteria=new CDbCriteria;
|
||||
|
||||
$criteria->compare('id',$this->id);
|
||||
$criteria->compare('candidato_id',$this->candidato_id);
|
||||
$criteria->compare('fecha',$this->fecha,true);
|
||||
$criteria->compare('tipo',$this->tipo,true);
|
||||
$criteria->compare('nombre_fichero',$this->nombre_fichero,true);
|
||||
|
||||
return new CActiveDataProvider($this, array(
|
||||
'criteria'=>$criteria,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
52
www/protected/views/candidato/_documentos.php
Normal file
52
www/protected/views/candidato/_documentos.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
?>
|
||||
|
||||
<div class="content nopadding ohidden">
|
||||
<div class="padding1020">
|
||||
<label><?php echo Yii::t('intranet', 'Currículums'); ?></label>
|
||||
|
||||
<div class="marginleft150">
|
||||
<?php $this->widget('ext.multimodelform.MultiModelForm',array(
|
||||
'id' => 'id_capacidad', //the unique widget id
|
||||
'addItemText' => '', // no quiero mostrar el enlace de añadir
|
||||
'removeText' => 'Eliminar',
|
||||
'removeConfirm' => '¿Desea eliminar esta capacidad?',
|
||||
'tableHtmlOptions' => array(
|
||||
'class' => 'sTable2 lf',
|
||||
),
|
||||
'tableView' => true,
|
||||
'formConfig' => $capacidadFormConfig, //the form configuration array
|
||||
'model' => $capacidad, //instance of the form model
|
||||
|
||||
//if submitted not empty from the controller,
|
||||
//the form will be rendered with validation errors
|
||||
'validatedItems' => $capacidadesValidas,
|
||||
|
||||
//array of member instances loaded from db
|
||||
'data' => $capacidad->findAll('candidato_id=:candidato_id', array(':candidato_id'=>$model->id)),
|
||||
|
||||
'removeHtmlOptions' => array(
|
||||
'class' => 'button plain',
|
||||
),
|
||||
));
|
||||
?>
|
||||
<br clear="all" />
|
||||
<div class="mmf_addlink">
|
||||
<?php
|
||||
echo CHtml::link('Añadir capacidad', '#', array(
|
||||
'class' => 'button plain',
|
||||
'rel' => '.id_capacidad_copy',
|
||||
'id' => 'id_capacidad',
|
||||
));
|
||||
|
||||
?>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,25 +1,5 @@
|
||||
<?php
|
||||
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl . '/js/custom/elements.js');
|
||||
/*Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl . '/js/plugins/wysiwyg/jquery.wysiwyg.js');
|
||||
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl . 'js/plugins/wysiwyg/wysiwyg.image.js');
|
||||
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl . 'js/plugins/wysiwyg/wysiwyg.link.js');
|
||||
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl . 'js/plugins/wysiwyg/wysiwyg.table.js');
|
||||
|
||||
$script=<<<HTML
|
||||
jQuery(document).ready(function() {
|
||||
jQuery('#wysiwyg').wysiwyg({
|
||||
initialContent: "",
|
||||
controls: {
|
||||
cut: { visible: true },
|
||||
copy: { visible: true },
|
||||
paste: { visible: true }
|
||||
}
|
||||
});
|
||||
});
|
||||
HTML;
|
||||
|
||||
Yii::app()->clientScript->registerScript('wysiwyg', $script, CClientScript::POS_END);*/
|
||||
|
||||
?>
|
||||
|
||||
<?php $form=$this->beginWidget('CActiveForm', array(
|
||||
|
||||
52
www/protected/views/candidatoDocumento/_form.php
Normal file
52
www/protected/views/candidatoDocumento/_form.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
Yii::app()->clientScript->registerScriptFile(Yii::app()->baseUrl . '/js/custom/elements.js');
|
||||
?>
|
||||
|
||||
<?php $form=$this->beginWidget('CActiveForm', array(
|
||||
'id'=>'candidato-documento-form',
|
||||
'enableAjaxValidation'=>false,
|
||||
'htmlOptions' => array('enctype' => 'multipart/form-data'),
|
||||
//'clientOptions'=>array('validateOnSubmit'=>true, 'validateOnChange'=>true),
|
||||
)); ?>
|
||||
|
||||
<div class="two_third last">
|
||||
<div class="notification msginfo">
|
||||
<a class="close"></a>
|
||||
<p>Los campos marcados con <span class="required">*</span> son obligatorios.</p>
|
||||
</div><!-- notification msginfo -->
|
||||
|
||||
<?php echo $form->errorSummary($model, "<a class='close'></a>", "", array('class'=>"notification msgerror")); ?>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
|
||||
|
||||
<div class="widgetbox two_third last form_default">
|
||||
<h3>
|
||||
<span>
|
||||
<legend><?php echo Yii::t('intranet', 'Currículum'); ?></legend>
|
||||
</span>
|
||||
</h3>
|
||||
<div class="content nopadding">
|
||||
<div class="padding1020">
|
||||
<?php echo $form->labelEx($model,'tipo', array('class'=>'nopadding')); ?>
|
||||
<div class="marginleft150">
|
||||
<?php echo CHtml::activeRadioButtonList($model, 'tipo', $model->OpcionesTipo, array(
|
||||
'template' => '{input}{label}',
|
||||
'separator' => ' ',
|
||||
)); ?>
|
||||
<?php echo $form->error($model,'tipo', array('class'=>'errortext')); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="padding1020 borderbottom">
|
||||
<?php echo $form->labelEx($model,'file'); ?>
|
||||
<div class="marginleft150">
|
||||
<?php echo CHtml::activeFileField($model, 'file'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
<div class="form_default">
|
||||
<button type="submit"><?php echo $model->isNewRecord ? 'Crear' : 'Guardar'; ?></button>
|
||||
</div>
|
||||
<?php $this->endWidget(); ?>
|
||||
39
www/protected/views/candidatoDocumento/_search.php
Normal file
39
www/protected/views/candidatoDocumento/_search.php
Normal file
@ -0,0 +1,39 @@
|
||||
<div class="wide form">
|
||||
|
||||
<?php $form=$this->beginWidget('CActiveForm', array(
|
||||
'action'=>Yii::app()->createUrl($this->route),
|
||||
'method'=>'get',
|
||||
)); ?>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->label($model,'id'); ?>
|
||||
<?php echo $form->textField($model,'id'); ?>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->label($model,'candidato_id'); ?>
|
||||
<?php echo $form->textField($model,'candidato_id'); ?>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->label($model,'fecha'); ?>
|
||||
<?php echo $form->textField($model,'fecha'); ?>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->label($model,'tipo'); ?>
|
||||
<?php echo $form->textField($model,'tipo',array('size'=>60,'maxlength'=>255)); ?>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php echo $form->label($model,'nombre_fichero'); ?>
|
||||
<?php echo $form->textField($model,'nombre_fichero',array('size'=>60,'maxlength'=>255)); ?>
|
||||
</div>
|
||||
|
||||
<div class="row buttons">
|
||||
<?php echo CHtml::submitButton('Search'); ?>
|
||||
</div>
|
||||
|
||||
<?php $this->endWidget(); ?>
|
||||
|
||||
</div><!-- search-form -->
|
||||
24
www/protected/views/candidatoDocumento/_view.php
Normal file
24
www/protected/views/candidatoDocumento/_view.php
Normal file
@ -0,0 +1,24 @@
|
||||
<div class="view">
|
||||
|
||||
<b><?php echo CHtml::encode($data->getAttributeLabel('id')); ?>:</b>
|
||||
<?php echo CHtml::link(CHtml::encode($data->id), array('view', 'id'=>$data->id)); ?>
|
||||
<br />
|
||||
|
||||
<b><?php echo CHtml::encode($data->getAttributeLabel('candidato_id')); ?>:</b>
|
||||
<?php echo CHtml::encode($data->candidato_id); ?>
|
||||
<br />
|
||||
|
||||
<b><?php echo CHtml::encode($data->getAttributeLabel('fecha')); ?>:</b>
|
||||
<?php echo CHtml::encode($data->fecha); ?>
|
||||
<br />
|
||||
|
||||
<b><?php echo CHtml::encode($data->getAttributeLabel('tipo')); ?>:</b>
|
||||
<?php echo CHtml::encode($data->tipo); ?>
|
||||
<br />
|
||||
|
||||
<b><?php echo CHtml::encode($data->getAttributeLabel('nombre_fichero')); ?>:</b>
|
||||
<?php echo CHtml::encode($data->nombre_fichero); ?>
|
||||
<br />
|
||||
|
||||
|
||||
</div>
|
||||
54
www/protected/views/candidatoDocumento/admin.php
Normal file
54
www/protected/views/candidatoDocumento/admin.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
$this->breadcrumbs=array(
|
||||
'Candidato Documentos'=>array('index'),
|
||||
'Manage',
|
||||
);
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'List CandidatoDocumento', 'url'=>array('index')),
|
||||
array('label'=>'Create CandidatoDocumento', 'url'=>array('create')),
|
||||
);
|
||||
|
||||
Yii::app()->clientScript->registerScript('search', "
|
||||
$('.search-button').click(function(){
|
||||
$('.search-form').toggle();
|
||||
return false;
|
||||
});
|
||||
$('.search-form form').submit(function(){
|
||||
$.fn.yiiGridView.update('candidato-documento-grid', {
|
||||
data: $(this).serialize()
|
||||
});
|
||||
return false;
|
||||
});
|
||||
");
|
||||
?>
|
||||
|
||||
<h1>Manage Candidato Documentos</h1>
|
||||
|
||||
<p>
|
||||
You may optionally enter a comparison operator (<b><</b>, <b><=</b>, <b>></b>, <b>>=</b>, <b><></b>
|
||||
or <b>=</b>) at the beginning of each of your search values to specify how the comparison should be done.
|
||||
</p>
|
||||
|
||||
<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button')); ?>
|
||||
<div class="search-form" style="display:none">
|
||||
<?php $this->renderPartial('_search',array(
|
||||
'model'=>$model,
|
||||
)); ?>
|
||||
</div><!-- search-form -->
|
||||
|
||||
<?php $this->widget('zii.widgets.grid.CGridView', array(
|
||||
'id'=>'candidato-documento-grid',
|
||||
'dataProvider'=>$model->search(),
|
||||
'filter'=>$model,
|
||||
'columns'=>array(
|
||||
'id',
|
||||
'candidato_id',
|
||||
'fecha',
|
||||
'tipo',
|
||||
'nombre_fichero',
|
||||
array(
|
||||
'class'=>'CButtonColumn',
|
||||
),
|
||||
),
|
||||
)); ?>
|
||||
12
www/protected/views/candidatoDocumento/create.php
Normal file
12
www/protected/views/candidatoDocumento/create.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
$this->breadcrumbs=array(
|
||||
Yii::t('intranet', 'Candidatos') => array('candidato/index'),
|
||||
$candidato->nombre . ' ' . $candidato->apellidos => $this->createUrl('candidato/view',array('id' => $candidato->id)),
|
||||
Yii::t('intranet', 'Currículums') => $this->createUrl('candidatoDocumento/index', array('cid'=>$candidato->id)),
|
||||
Yii::t('intranet', 'Añadir currículum'),
|
||||
);
|
||||
|
||||
$this->pageTitle=Yii::t('intranet', 'Añadir currículum de candidato');
|
||||
?>
|
||||
|
||||
<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>
|
||||
90
www/protected/views/candidatoDocumento/index.php
Normal file
90
www/protected/views/candidatoDocumento/index.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
$this->breadcrumbs=array(
|
||||
Yii::t('intranet', 'Candidatos') => array('candidato/index'),
|
||||
$candidato->nombre . ' ' . $candidato->apellidos => array('candidato/view','id'=>$candidato->id),
|
||||
Yii::t('intranet', 'Currículums'),
|
||||
);
|
||||
|
||||
$this->pageTitle = Yii::t('intranet', 'Gestión de currículums de candidato');
|
||||
|
||||
?>
|
||||
|
||||
<?php
|
||||
echo CHtml::link(
|
||||
Yii::t('intranet', 'Añadir currículum'),
|
||||
$this->createUrl('candidatoDocumento/create', array('cid'=>$candidato->id)),
|
||||
array(
|
||||
'class' => 'anchorbutton button_white',
|
||||
)
|
||||
|
||||
);
|
||||
?>
|
||||
|
||||
<br clear="all" />
|
||||
<br clear="all" />
|
||||
|
||||
<div class="widgetbox">
|
||||
<div class="content nopadding ohidden">
|
||||
<?php
|
||||
$columns = array(
|
||||
array(
|
||||
'name' => 'tipo',
|
||||
'headerHtmlOptions'=>array(
|
||||
'style' => 'width:75px;',
|
||||
'class' => 'head0',
|
||||
),
|
||||
'cssClassExpression' => '"con1"',
|
||||
),
|
||||
array(
|
||||
'type' => 'html',
|
||||
'name' => 'nombre_fichero',
|
||||
'value' => 'CHtml::link(CHtml::encode($data->nombre_fichero), array("download", "id"=>$data->id));',
|
||||
'headerHtmlOptions'=>array(
|
||||
'class' => 'head1',
|
||||
),
|
||||
'cssClassExpression' => '"con0"',
|
||||
),
|
||||
array(
|
||||
'type' => 'raw',
|
||||
'name' => 'fecha',
|
||||
'value' => 'Time::timeAgoInWords($data->fecha);',
|
||||
'headerHtmlOptions'=>array(
|
||||
'style' => 'width:150px;',
|
||||
'class' => 'head0',
|
||||
),
|
||||
'cssClassExpression' => '"con1"',
|
||||
),
|
||||
array(
|
||||
'header'=>Yii::t('intranet', 'Acciones'),
|
||||
'class'=>'CButtonColumn',
|
||||
'headerHtmlOptions'=>array(
|
||||
'style' => 'width:55px;',
|
||||
'class' => 'head0',
|
||||
),
|
||||
'template'=>'{delete}',
|
||||
'cssClassExpression' => '"con1"',
|
||||
),
|
||||
);
|
||||
|
||||
$pageSize = Yii::app()->user->getState('pageSize', Yii::app()->params['defaultPageSize']);
|
||||
$dataProvider->getPagination()->setPageSize($pageSize);
|
||||
|
||||
$this->widget('application.extensions.SelGridView', array(
|
||||
'id'=>'documentos-grid',
|
||||
'dataProvider'=>$dataProvider,
|
||||
'columns'=>$columns,
|
||||
'cssFile' => Yii::app()->baseUrl . '/css/gridview3.css',
|
||||
'itemsCssClass' => 'sTable3',
|
||||
'pagerCssClass' => 'dataTables_paginate',
|
||||
'template' => '{items}{pager}',
|
||||
'emptyText' => Yii::t('intranet', 'Este candidato no tiene documentos'),
|
||||
'selectableRows' => 1,
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
18
www/protected/views/candidatoDocumento/update.php
Normal file
18
www/protected/views/candidatoDocumento/update.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
$this->breadcrumbs=array(
|
||||
'Candidato Documentos'=>array('index'),
|
||||
$model->id=>array('view','id'=>$model->id),
|
||||
'Update',
|
||||
);
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'List CandidatoDocumento', 'url'=>array('index')),
|
||||
array('label'=>'Create CandidatoDocumento', 'url'=>array('create')),
|
||||
array('label'=>'View CandidatoDocumento', 'url'=>array('view', 'id'=>$model->id)),
|
||||
array('label'=>'Manage CandidatoDocumento', 'url'=>array('admin')),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1>Update CandidatoDocumento <?php echo $model->id; ?></h1>
|
||||
|
||||
<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>
|
||||
27
www/protected/views/candidatoDocumento/view.php
Normal file
27
www/protected/views/candidatoDocumento/view.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
$this->breadcrumbs=array(
|
||||
'Candidato Documentos'=>array('index'),
|
||||
$model->id,
|
||||
);
|
||||
|
||||
$this->menu=array(
|
||||
array('label'=>'List CandidatoDocumento', 'url'=>array('index')),
|
||||
array('label'=>'Create CandidatoDocumento', 'url'=>array('create')),
|
||||
array('label'=>'Update CandidatoDocumento', 'url'=>array('update', 'id'=>$model->id)),
|
||||
array('label'=>'Delete CandidatoDocumento', 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Are you sure you want to delete this item?')),
|
||||
array('label'=>'Manage CandidatoDocumento', 'url'=>array('admin')),
|
||||
);
|
||||
?>
|
||||
|
||||
<h1>View CandidatoDocumento #<?php echo $model->id; ?></h1>
|
||||
|
||||
<?php $this->widget('zii.widgets.CDetailView', array(
|
||||
'data'=>$model,
|
||||
'attributes'=>array(
|
||||
'id',
|
||||
'candidato_id',
|
||||
'fecha',
|
||||
'tipo',
|
||||
'nombre_fichero',
|
||||
),
|
||||
)); ?>
|
||||
@ -45,9 +45,9 @@ $pestañas = array(
|
||||
),
|
||||
array(
|
||||
'label' => Yii::t('intranet', 'Currículums'),
|
||||
'url' => array('/usuario'),
|
||||
'url' => $this->createUrl('candidatoDocumento/index', array('cid'=>$candidatoId)),
|
||||
'linkOptions' => array('class'=>'curriculum'),
|
||||
'active' => ($this->id == 'curriculum')
|
||||
'active' => ($this->id == 'candidatoDocumento')
|
||||
),
|
||||
array(
|
||||
'label' => Yii::t('intranet', 'Historial'),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user