Distribution.php 19.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<?php
/**
 * @file
 * Contains \Drupal\query_example\Controller\QueryExampleController.
 */

namespace Drupal\epal\Controller;

use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\Core\Controller\ControllerBase;

use Symfony\Component\HttpFoundation\RedirectResponse;
16
use Drupal\Core\Database\Database;
17 18 19 20 21
use Drupal\Core\Database\Connection;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;

22 23 24 25 26
//use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\TypedData\Plugin\DataType\TimeStamp;

use Drupal\Core\Language\LanguageManagerInterface;

27 28 29 30 31 32
class Distribution extends ControllerBase {

	protected $entity_query;
  protected $entityTypeManager;
  protected $logger;
  protected $connection;
33 34
	protected $language;
	protected $currentuser;
35 36 37

	protected $pendingStudents = array();
	protected $choice_id = 1;
38
	protected $globalCounterId = 1;
39 40 41 42 43

	public function __construct(
		EntityTypeManagerInterface $entityTypeManager,
		QueryFactory $entity_query,
		Connection $connection,
44

45 46 47 48
		LoggerChannelFactoryInterface $loggerChannel)
		{
			$this->entityTypeManager = $entityTypeManager;
			$this->entity_query = $entity_query;
49
			$connection = Database::getConnection();
50
			$this->connection = $connection;
51 52 53 54
			$language =  \Drupal::languageManager()->getCurrentLanguage()->getId();
			$this->language = $language;
			$currentuser = \Drupal::currentUser()->id();
			$this->currentuser = $currentuser;
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
			$this->logger = $loggerChannel->get('epal');
    }

	public static function create(ContainerInterface $container)
    {
        return new static(
          $container->get('entity_type.manager'),
          $container->get('entity.query'),
          $container->get('database'),
          $container->get('logger.factory')
      );
    }


	public function createDistribution(Request $request) {

71 72 73
		$numDistributions = 3;
		$sizeOfBlock = 100000;

74
		//POST method is checked
75 76 77 78
		if (!$request->isMethod('POST')) {
			return $this->respondWithStatus([
					"message" => t("Method Not Allowed")
				], Response::HTTP_METHOD_NOT_ALLOWED);
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
    }

		//user validation
		$authToken = $request->headers->get('PHP_AUTH_USER');
		$users = $this->entityTypeManager->getStorage('user')->loadByProperties(array('name' => $authToken));
		$user = reset($users);
		if (!$user) {
				return $this->respondWithStatus([
								'message' => t("User not found"),
						], Response::HTTP_FORBIDDEN);
		}

		//user role validation
		$roles = $user->getRoles();
		$validRole = false;
		foreach ($roles as $role)
			if ($role === "ministry") {
				$validRole = true;
				break;
			}
		if (!$validRole) {
				return $this->respondWithStatus([
								'message' => t("User Invalid Role"),
						], Response::HTTP_FORBIDDEN);
		}
104 105


106 107 108
		$transaction = $this->connection->startTransaction();

		try {
109

110
			//initialize/empty epal_student_class if there are already data in it!
111 112
			//$this->connection->delete('epal_student_class')->execute();
			$this->initializeResults();
113

114 115
			//$limitUp_class = $this->retrieveCapacityLimitUp("Α");
			$limitUp_class = $this->retrieveCapacityLimitUp("1");
116
			//print_r("<br> ΑΝΩΤΑΤΟ ΟΡΙΟ ΜΑΘΗΤΩΝ: " . $limitUp_class);
117

118 119
			while ($this->choice_id <= $numDistributions)	 {

120
				//print_r("<br>ΠΕΡΑΣΜΑ: " . $this->choice_id);
121 122 123

				//υπολογισμός πλήθους non-finalized αιτήσεων για να καθοριστεί ο αριθμός των fetches που θα κάνουμε με συγκεκριμένο sizeOfBlock
				if ($this->choice_id === 1)	{
124 125 126
					$sCon = $this->connection->select('epal_student', 'eStudent')
																		->fields('eStudent', array('id'));
			 	  $numData = $sCon->countQuery()->execute()->fetchField();
127
					//print_r("<br>numData: " .  $numData);
128 129 130 131 132 133
				}

				$j = 1;
				$num = 1;
				if ($this->choice_id === 1) {
							while ($num <= $numData)	{
134

135
								//print_r("<br>FETCH: " .  $j);
136 137 138 139 140 141
								$sCon = $this->connection->select('epal_student', 'eStudent')
																					->fields('eStudent', array('id', 'name', 'currentclass', 'currentepal', 'points'))
																			    ->condition('eStudent.id', 1+ $sizeOfBlock*($j-1), '>=')
																					->condition('eStudent.id', $j*$sizeOfBlock, '<=');
								$epalStudents = $sCon->execute()->fetchAll(\PDO::FETCH_OBJ);

142 143
								$this->locateStudent($this->choice_id, $epalStudents);

144
								$num = $num + sizeof($epalStudents);
145 146 147 148
								$j = $j + 1;
							}
						}
				else {
149 150 151 152 153 154 155 156 157 158 159 160

								if (sizeof($this->pendingStudents) != 0)	{
									$sCon = $this->connection->select('epal_student', 'eStudent')
																						->fields('eStudent', array('id', 'name', 'currentclass', 'currentepal', 'points'))
																						->condition('eStudent.id', $this->pendingStudents, 'IN');
									$epalStudents = $sCon->execute()->fetchAll(\PDO::FETCH_OBJ);

									$this->locateStudent($this->choice_id, $epalStudents);
								}
								else {	//αν δεν υπάρχουν εκκρεμότητες, μην συνεχίζεις με άλλο πέρασμα
									break;
								}
161 162 163 164 165 166
						}

				//Για κάθε σχολείο βρες τα τμήματα
				//Για κάθε τμήμα βρες αν χωράνε και διευθέτησε (checkCapacityAndArrange)
				//checkCapacityAndArrange (school_id, class_id, sectorORcourse_id, limitUp, schoolCapacity)

167 168 169 170 171
				$sCon = $this->connection->select('eepal_school_field_data', 'eSchool')
																	->fields('eSchool', array('id', 'capacity_class_a'));
																	//->condition('eSchool.id', 151, '>=')
																	//->condition('eSchool.id', 153, '<=');	//προσαρμοσμένο για τα demo data --> να αλλάξει
				$eepalSchools = $sCon->execute()->fetchAll(\PDO::FETCH_OBJ);
172 173 174

				foreach ($eepalSchools as $eepalSchool)	{

175
						$this->checkCapacityAndArrange($eepalSchool->id, "1", "-1", $limitUp_class, $eepalSchool->capacity_class_a);
176

177 178 179 180
						$sCon = $this->connection->select('eepal_sectors_in_epal_field_data', 'eSchool')
																			->fields('eSchool', array('epal_id', 'sector_id', 'capacity_class_sector'))
																			->condition('eSchool.epal_id', $eepalSchool->id, '=');
						$eepalSectorsInEpal = $sCon->execute()->fetchAll(\PDO::FETCH_OBJ);
181
						foreach ($eepalSectorsInEpal as $eepalSecInEp)	{
182
							$this->checkCapacityAndArrange($eepalSchool->id, "2", $eepalSecInEp->sector_id, $limitUp_class, $eepalSecInEp->capacity_class_sector);
183 184
					  }

185 186 187 188
						$sCon = $this->connection->select('eepal_specialties_in_epal_field_data', 'eSchool')
																			->fields('eSchool', array('epal_id', 'specialty_id', 'capacity_class_specialty'))
																			->condition('eSchool.epal_id', $eepalSchool->id, '=');
						$eepalSpecialtiesInEpal = $sCon->execute()->fetchAll(\PDO::FETCH_OBJ);
189
						foreach ($eepalSpecialtiesInEpal as $eepalSpecialInEp)	{
190
							$this->checkCapacityAndArrange($eepalSchool->id, "3", $eepalSpecialInEp->specialty_id, $limitUp_class, $eepalSpecialInEp->capacity_class_specialty);
191 192
							//Δ' Λυκείου
							$this->checkCapacityAndArrange($eepalSchool->id, "4", $eepalSpecialInEp->specialty_id, $limitUp_class, $eepalSpecialInEp->capacity_class_specialty);
193 194 195 196 197 198 199 200
						}

					} //end for each school/department

					$this->choice_id++;

	  	} //end while

201

202 203 204 205 206
		}	//end try

		catch (\Exception $e) {
			$this->logger->warning($e->getMessage());
			$transaction->rollback();
207
			return $this->respondWithStatus([
208 209 210 211
					"message" => t("An unexpected problem occured")
				], Response::HTTP_INTERNAL_SERVER_ERROR);
		}

212 213 214 215
		//return new RedirectResponse($this->redirectUrl . '?auth_token=' . $epalToken.'&auth_role=director', 302, []);
		//return new RedirectResponse("../eepal/dist/#/minister/minister-view");

		/*
216
		return $this->respondWithStatus([
217 218
					"message" => t("Distribution has made successfully")
				], Response::HTTP_OK);
219 220 221 222 223 224 225 226 227 228 229 230 231
		*/
		$postData = null;
		if ($content = $request->getContent()) {
				$postData = json_decode($content);
				return $this->respondWithStatus([
						'message' => "Distribution has made successfu",
				], Response::HTTP_OK);
			}
			else {
				return $this->respondWithStatus([
						'message' => t("post with no data"),
				], Response::HTTP_BAD_REQUEST);
			}
232 233 234 235 236 237 238 239 240

	}


	public function locateStudent($choice_id, &$epalStudents)	{

		$epal_dist_id = -1;
		$specialization_id = -1;

241
		$transaction = $this->connection->startTransaction();
242

243
		try {
244 245

			foreach ($epalStudents as $epalStudent)	{
246 247
				//print_r("<br>ΚΑΤΑΝΟΜΗ ΜΑΘΗΤΩΝ ΝΟ: " . $choice_id);
				//print_r("<br>ΜΑΘΗΤΗΣ: " .  $epalStudent->id);
248 249 250 251 252 253

				$clCon = $this->connection->select('epal_student_epal_chosen', 'epals')
					->fields('epals', array('student_id', 'epal_id', 'choice_no'))
					->condition('epals.student_id', $epalStudent->id , '=')
					->condition('epals.choice_no', $choice_id , '=');
				$epalSchoolsChosen = $clCon->execute()->fetchAll(\PDO::FETCH_OBJ);
254 255 256

				if (sizeof($epalSchoolsChosen) !==  0)	{
					$epalSchoolChos = reset($epalSchoolsChosen);
257
					//print_r(" SCHOOL_ID:" . $epalSchoolChos->epal_id . " STUDENT_ID " . $epalStudent->id);
258 259 260 261 262 263 264
					$epal_dist_id = $epalSchoolChos->epal_id;

					if ($epalStudent->currentclass === "2")	{
						$clCon = $this->connection->select('epal_student_sector_field', 'sectors')
							->fields('sectors', array('student_id', 'sectorfield_id'))
							->condition('sectors.student_id', $epalStudent->id , '=');
						$epalSectorChosen = $clCon->execute()->fetchAll(\PDO::FETCH_OBJ);
265 266
						$epalSecChos = reset($epalSectorChosen);
					}
267 268
					//Δ'Λυκείου - Γ' Λυκείου
					elseif ($epalStudent->currentclass === "3" || $epalStudent->currentclass === "4")	{
269 270 271 272
						$clCon = $this->connection->select('epal_student_course_field', 'courses')
							->fields('courses', array('student_id', 'coursefield_id'))
							->condition('courses.student_id', $epalStudent->id , '=');
						$epalCourseChosen = $clCon->execute()->fetchAll(\PDO::FETCH_OBJ);
273 274 275
						$epalCourChos = reset($epalCourseChosen);
					}

276 277
					if ($epalStudent->currentclass === "2")
						$specialization_id = $epalSecChos->sectorfield_id;
278 279
					//Δ'Λυκείου - Γ' Λυκείου
					elseif ($epalStudent->currentclass === "3" || $epalStudent->currentclass === "4")
280
						$specialization_id = $epalCourChos->coursefield_id;
281 282 283
					else
						$specialization_id = -1;

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

				 //$currentTime = \Drupal\Core\TypedData\Plugin\DataType\TimeStamp::getDateTime();
					$timestamp = strtotime(date("Y-m-d"));
					$this->connection->insert('epal_student_class')->fields(
						array('id' => $this->globalCounterId++,
							'uuid' => \Drupal::service('uuid')->generate(),
							'langcode' => $this->language,
							'user_id' => $this->currentuser,
							'student_id'=> $epalStudent->id,
							'epal_id'=> $epal_dist_id,
							'currentclass' => $epalStudent->currentclass,
							'currentepal' => $epalStudent->currentepal,
							'specialization_id' => $specialization_id,
							'points' => $epalStudent->points,
							'distribution_id' => $choice_id,
							'status' => 1,
							'created' => $timestamp,
							'changed' => $timestamp,)
					)->execute();
303 304 305 306 307 308 309 310 311

			} //end if

		}	//foreach

	}

	catch (\Exception $e) {
		$this->logger->warning($e->getMessage());
312
		$transaction->rollback();
313 314 315 316 317 318 319 320 321 322 323 324 325 326
		return $this->respondWithStatus([
					"message" => t("An unexpected problem occured during locateStudent Method of Distribution")
				], Response::HTTP_INTERNAL_SERVER_ERROR);
	}

	return $this->respondWithStatus([
			"message" => t("locateStudent Method of Distribution has made successfully")
		], Response::HTTP_OK);

	}


 public function retrieveCapacityLimitUp($className) {

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
	 $transaction = $this->connection->startTransaction();

	 try {
		 $clCon = $this->connection->select('epal_class_limits', 'classLimits')
			 ->fields('classLimits', array('limit_up'))
			 ->condition('classLimits.name', $className, '=');
		 $results = $clCon->execute()->fetchAll(\PDO::FETCH_OBJ);
		 $row = reset($results);
 	}
	catch (\Exception $e) {
		$this->logger->warning($e->getMessage());
		$transaction->rollback();
		return $this->respondWithStatus([
					"message" => t("An unexpected problem occured during retrieveCapacityLimitUp Method of Distribution")
				], Response::HTTP_INTERNAL_SERVER_ERROR);
	}

	return $row->limit_up;
345 346 347 348
 }

	public function checkCapacityAndArrange($epalId, $classId, $secCourId, $limitup, $capacity)	{

349 350 351 352 353 354 355 356 357 358 359
		$transaction = $this->connection->startTransaction();

		try {

			$clCon = $this->connection->select('epal_student_class', 'studentClass')
				->fields('studentClass', array('epal_id', 'student_id', 'points', 'currentepal', 'currentclass', 'specialization_id'))
				->condition('studentClass.epal_id', $epalId, '=')
				->condition('studentClass.currentclass', $classId, '=')
				->condition('studentClass.specialization_id', $secCourId, '=');
			$epalStudentClass = $clCon->execute()->fetchAll(\PDO::FETCH_OBJ);

360
			//print_r("<br> ΣΧΟΛΕΙΟ: " .  $epalId . " ΤΑΞΗ: "  . $classId . " ΤΟΜΕΑΣ/ΕΙΔΙΚΟΤΗΤΑ: " . $secCourId .  " ΧΩΡΗΤΙΚΟΤΗΤΑ: " . sizeof($epalStudentClass));
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380

			//ΕΠΙΠΛΕΟΝ ΕΠΙΠΕΔΟ ΑΣΦΑΛΕΙΑΣ: αν δεν υπάρχει ο συγκεκριμένος τομέας/ειδικότητα στο σχολείο
			//ο μαθητής που τοποθετήθηκε με την locateStudent να διαγραφεί
			//Σημείωση: κανονικά κάτι τέτοιο δεν μπορεί να συμβεί από το front-end (δηλ. μαθητής να δηλώσει τομέα/ειδικότητα που δεν προσφέρεται..)
			//ΑΝ ΜΠΕΙ ΠΡΕΠΕΙ ΝΑ ΕΝΣΩΜΑΤΩΘΕΙ ΣΤΗΝ LOCATESTUDENT..
			/*
			if (sizeof($epalStudentClass) === 0)	{
				//print_r("<br>ΜΠΗΚΑ! ");
				foreach ($epalStudentClass as $epalStudCl)	{
					//print_r("<br>ΜΠΗΚΑ! ΜΑΘΗΤΗΣ: " .  $epalStudCl->student_id);
					$query = $this->connection->delete('epal_student_class')
													->condition('student_id', $epalStudCl->student_id)
													->execute();
					}
			}
			*/
			//ΤΕΛΟΣ

			$limit = $limitup * $capacity;
			if (sizeof($epalStudentClass) > $limit)	{
381
				//print_r("<br>ΥΠΕΡΧΕΙΛΙΣΗ!");
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
				foreach ($epalStudentClass as $epalStudCl)	{
					//Υπολογισμός μορίων του μαθητή και (πιθανή) αποθήκευσή τους
					//ΣΗΜΕΙΩΣΗ: Ο υπoλογισμός γίνεται στο front-end

					//$points = $this->calculatePoints();
					/*
					$query = $this->connection->update('epal_student');
					$query->fields([
						'points' =>$points,
					]);
					$query->condition('id',$epalStudCl->student_id);
					$query->execute();
					*/

				}
				$this->makeSelectionOfStudents($epalStudentClass,$limit);
398
			}
399 400 401 402 403 404
			else { //αφαίρεσε όσους μαθητές βρίσκονται στον πίνακα εκκρεμοτήτων
				foreach ($epalStudentClass as $epalStudCl) {
					if ($this->choice_id !== 1)
						////διέγραψε τον μαθητή από τον πίνακα εκκρεμοτήτων (αν βρίσκεται εκεί)
						$this->removeFromPendingStudents($epalStudCl->student_id);
				}
405 406
			}

407
	}	//end try
408

409 410 411
	catch (\Exception $e) {
		$this->logger->warning($e->getMessage());
		$transaction->rollback();
412
		return $this->respondWithStatus([
413 414 415 416 417
					"message" => t("An unexpected problem occured during checkCapacityAndArrange Method of Distribution")
				], Response::HTTP_INTERNAL_SERVER_ERROR);
	}

	return $this->respondWithStatus([
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
				"message" => t("checkCapacityAndArrange Method of Distribution has made successfully")
			], Response::HTTP_OK);

	}


	public function removeFromPendingStudents($val)	{
		if(($key = array_search($val, $this->pendingStudents)) !== false) {
		   unset($this->pendingStudents[$key]);
		}
		//$this->pendingStudents = array_diff($this->pendingStudents, array($val));
	}

	public function makeSelectionOfStudents(&$students, $limit)	{
		//συνάρτηση επιλογής μαθητών σε περίπτωση υπερχείλισης
		// (1) έχουν απόλυτη προτεραιότητα όσοι ήδη φοιτούσαν στο σχολείο (σε περίπτωση που φοιτούσαν περισσότεροι από την χωρητικότητα, τους δεχόμαστε όλους)
		// (2) αν απομένουν κενές θέσεις, επέλεξε από τους εναπομείναντες μαθητές αυτούς με τα περισσότερα μόρια. Σε περίπτωση ισοβαθμίας δεχόμαστε όλους όσους ισοβαθμούν.
		//αυτοδίκαια έχουν προτεραιότητα όσοι ήδη φοιτούσαν στο σχολείο

		foreach($students as $student)	{
438
			$student->student_id;
439
			//print_r("<br>STUDENT_ID:" . $student->student_id);
440 441 442 443 444
		}

		//εύρεση αριθμού μαθητών που ήδη φοιτούσαν στο σχολείο
		$cnt = 0;
		foreach($students as $student)	{
445
			if ($student->currentepal === $student->epal_id) {
446 447 448
				$cnt++;
				if ($this->choice_id !== 1)
					////διέγραψε τον μαθητή από τον πίνακα εκκρεμοτήτων (αν βρίσκεται εκεί)
449
					$this->removeFromPendingStudents($student->student_id);
450 451
			}
		}
452
		//print_r("<br>#ΕΓΓΡΑΦΩΝ ΠΟΥ ΟΙ ΜΑΘΗΤΕΣ ΦΟΙΤΟΥΣΑΝ ΗΔΗ:" . $cnt);
453 454

		$newlimit = $limit - $cnt;
455 456
		//print_r("<br>ΑΝΩΤΑΤΟ ΟΡΙΟ ΜΑΘΗΤΩΝ:" . $limit);
		//print_r("<br>#ΜΑΘΗΤΩΝ ΓΙΑ ΝΑ ΕΠΙΛΕΓΟΥΝ ΜΕ ΜΟΡΙΑ:" . $newlimit);
457 458 459

		$points_arr = [];
		foreach($students as $student)	{
460 461
			if ($student->currentepal !== $student->epal_id)
				$points_arr[] = $student->points;
462
		}
463

464
		rsort($points_arr);
465 466
		//for ($i=0; $i < sizeof($points_arr); $i++)
			//print_r("<br>ΜΟΡΙΑ ΜΕΤΑ ΤΗΝ ΤΑΞΙΝΟΜΙΣΗ: " . $points_arr[$i]);
467

468
		//print_r("<br>ΟΡΙΟ ΜΟΡΙΩΝ: " . $points_arr[$newlimit-1]);
469

470 471
		$transaction = $this->connection->startTransaction();

472
		foreach($students as $student)	{
473 474
			if ($student->currentepal !== $student->epal_id)	{
				if ($student->points < $points_arr[$newlimit-1]) {
475
					//print_r("<br>ΣΕ ΕΚΚΡΕΜΟΤΗΤΑ - ΔΙΑΓΡΑΦΗ: " . $student->student_id);
476
					//βάλε τον μαθητή στον πίνακα εκκρεμοτήτων και διέγραψέ τον από τον προσωρινό πίνακα αποτελεσμάτων
477 478 479 480 481 482 483 484 485 486 487 488 489 490
					array_push($this->pendingStudents, $student->student_id);
					try {
						$this->connection->delete('epal_student_class')
													->condition('student_id', $student->student_id)
													->execute();
					}
					catch (\Exception $e) {
						$this->logger->warning($e->getMessage());
						$transaction->rollback();
						return $this->respondWithStatus([
									"message" => t("An unexpected problem occured during DELETE proccess in makeSelectionOfStudents Method of Distribution")
								], Response::HTTP_INTERNAL_SERVER_ERROR);
					}

491 492 493 494
				}
				else {
					if ($this->choice_id !== 1)
						//διέγραψε τον μαθητή από τον πίνακα εκκρεμοτήτων (αν βρίσκεται εκεί)
495
						$this->removeFromPendingStudents($student->student_id);
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
				}
			}
		}

		return $this->respondWithStatus([
				"message" => t("makeSelectionOfStudents Method of Distribution has made successfully")
			], Response::HTTP_OK);
	}

	public function calculatePoints()	{

			return rand(0,20);

	}

	private function respondWithStatus($arr, $s) {
				$res = new JsonResponse($arr);
				$res->setStatusCode($s);
				return $res;
		}

517 518 519 520 521 522 523 524 525 526 527 528
		private function initializeResults() {

			//initialize/empty epal_student_class if there are already data in it!
			try  {
				$this->connection->delete('epal_student_class')->execute();
			}
			catch (\Exception $e) {
				$this->logger->warning($e->getMessage());
				return $this->respondWithStatus([
							"message" => t("An unexpected problem occured during initializeResults Method of Distribution")
						], Response::HTTP_INTERNAL_SERVER_ERROR);
			}
529 530 531



532 533 534 535 536
		}




537
}