File: D:/HostingSpaces/SBogers10/zelfverkopen.komma.pro/app/KommaApp/Properties/PropertyService.php
<?php
namespace App\KommaApp\Properties;
use App\KommaApp\Realworks\Models\RealworkObject;
use App\KommaApp\Realworks\Models\ObjectDetailsTranslation;
use GuzzleHttp\Client;
use Illuminate\Database\Eloquent\Collection;
class PropertyService
{
const STATUS_AVAILABLE_SOLD = 'Verkocht';
const STATUS_SOLD_UNDER_CONDITIONS = 'Verkocht onder voorbehoud';
public function getPropertyPriceFilters()
{
$price = 0;
$priceSteps = 100000;
$maxPrice = 1000000;
$priceOptions = [];
do {
$price += $priceSteps;
$priceOptions[] = (object)[
'value' => $price,
'html' => '€ ' . number_format($price, 0, ',', '.')
];
} while ($price < $maxPrice);
return $priceOptions;
}
/**
* Generate the base property query
*
* @return mixed
*/
private function getBasePropertyQueryBuilder(){
return ObjectDetailsTranslation::join('object_details', 'object_details_translations.object_details_id', '=', 'object_details.id')
->join('objects', 'object_details.object_id', '=', 'objects.id')
->join('koop', 'object_details.id', '=', 'koop.object_details_id' )
->join('koop_translations', 'koop.id', '=', 'koop_translations.koop_id' )
->select('object_details_translations.*', 'objects.system_id', 'objects.id as object_id', 'object_details.long','object_details.lat', 'koop_translations.koop_prijs')
->orderBy('datum_invoer', 'desc');
}
/**
* Get the array of relations
*/
private function getPropertyRelationsArray(){
return [
'translatable',
'translatable.object',
'translatable.koop',
'translatable.koop.translation',
];
}
public function getProperties($pagination = true, $itemsPerPage = 12, $withFilters = []){
$properties = $this->getBasePropertyQueryBuilder();
// Use with Relations, because load can't be used in combination with pagination
$properties = $properties->with($this->getPropertyRelationsArray());
if(sizeof($withFilters) !== 0) $properties = $this->addFilterRules($properties, $withFilters);
// Get by pagination or all
if($pagination) $properties = $properties->paginate($itemsPerPage);
else $properties = $properties->get();
// Decode the raw json because we need those data
foreach ($properties as $property) {
$this->convertPropertyForViewData($property);
$this->bindMediaToProperty($property);
}
return $properties;
}
// Create shorter function for filters function
public function getPropertiesWithFilters($filters, $pagination = true, $itemsPerPage = 12){
return $this->getProperties($pagination, $itemsPerPage, $filters);
}
/*
* Append addition filter rules
*/
private function addFilterRules($queryBuilder, $withFilters){
foreach($withFilters as $filter => $value){
debug($filter. ' : '. $value);
switch ($filter){
case ('minimumPrice'):
$queryBuilder = $queryBuilder->where('koop_translations.koop_prijs', '>=', $value);
break;
case ('maximumPrice'):
$queryBuilder = $queryBuilder->where('koop_translations.koop_prijs', '<=', $value);
break;
case ('location'):
$queryBuilder = $queryBuilder->where('object_details_translations.woonplaats', 'LIKE', '%'.$value.'%');
break;
}
}
return $queryBuilder;
}
public function getProperty($objectId)
{
if(!$property = $this->getBasePropertyQueryBuilder()
->where('objects.id', '=', $objectId)
->first()) throw abort(404);
if(!isset($property->long) || !isset($property->lat) ) {
$this->getLongAndLatOfProperty($property);
}
$this->convertPropertyForViewData($property);
$this->bindMediaToProperty($property);
return $property;
}
/**
* Get the properties for the propertiesRow
* In general this means 2 not sold and 1 sold property
* And if there is no sold property available then we use 3 not sold
*
* @return mixed
*/
public function getPropertiesForRow()
{
// Get the latest sold property
$soldObject = $this->getBasePropertyQueryBuilder()
->whereIn('status_beschikbaarheid', [$this::STATUS_AVAILABLE_SOLD, $this::STATUS_SOLD_UNDER_CONDITIONS])
->first();
// Determine the amount of not sold properties must get
if ( ! $soldObject) $amountForSaleProperties = 3;
else $amountForSaleProperties = 2;
// Get latest properties which aren't sold
$properties = $this->getBasePropertyQueryBuilder()
->where('status_beschikbaarheid', '!=', $this::STATUS_AVAILABLE_SOLD)
->take($amountForSaleProperties)
->get();
// Push sold object to the end if found
if ($soldObject) $properties->push($soldObject);
//Load Relations
// We do this here to reduce the amount of queries that needs to be executed
$properties = $properties->load($this->getPropertyRelationsArray());
// Decode the raw json because we need those data
foreach ($properties as $property) {
$this->convertPropertyForViewData($property);
$this->bindMediaToProperty($property);
}
return $properties;
}
private function convertPropertyForViewData(&$property)
{
// Create slug for this property
$property->slug = 'woning-' . \Str::slug($property->system_id) . '-' . \Str::slug($property->woonplaats) . '-' . \Str::slug($property->straatnaam) . '-' . \Str::slug($property->huisnummer);
if (isset($property->huisnummer_toevoeging) && $property->huisnummer_toevoeging != '') {
$property->slug .= '-' . \Str::slug($property->huisnummer_toevoeging);
}
// Convert location to lowercase and capitalize by word
$property->location = ucwords(strtolower($property->woonplaats));
// Get the price of the property
if (isset($property->translatable->koop)) {
$property->price = $property->translatable->koop->translation->koop_prijs;
}elseif (isset($property->translatable->huur)) {
$property->price = $property->translatable->huur->translation->huur_prijs;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, '', 4);
}
// Convert the price to right format
if (isset($property->price)) {
$property->price_formated = number_format($property->price, 0, ',', '.');
}else {
$property->price_formated = '';
}
// Convert status
switch ($property->status_beschikbaarheid) {
case ('Beschikbaar'):
$property->status = 1;
break;
case ('Verkocht'):
$property->status = 2;
break;
case ('Verkocht onder voorbehoud'):
$property->status = 3;
break;
case ('Onder bod'):
$property->status = 4;
break;
case ('Ingetrokken'):
$property->status = 5;
break;
default:
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'status_beschikbaarheid', 2,
$property->status_beschikbaarheid);
$property->status = 0;
break;
}
// Detect if the raw json data is found
if (isset($property->translatable->object->raw_json)) {
// Decode and append the needed variables to the property
$propertyJson = json_decode($property->translatable->object->raw_json);
// Get show price variable
if (isset($propertyJson->Web) && isset($propertyJson->Web->PrijsTonen)) {
if ($propertyJson->Web->PrijsTonen == 'ja') {
$property->showPrice = true;
}elseif ($propertyJson->Web->PrijsTonen == 'nee') {
$property->showPrice = false;
}// Unexpected variable
else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Web->PrijsTonen', 2,
$propertyJson->Web->PrijsTonen);
}
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Web(->PrijsTonen)');
}
// Get Values of Property
if (isset($propertyJson->Wonen)) {
// Load global information of object
// Get Floors information
if (isset($propertyJson->Wonen->Verdiepingen)) {
// Amount of floors
if (isset($propertyJson->Wonen->Verdiepingen->Aantal)) {
$property->amountOfFloors = $propertyJson->Wonen->Verdiepingen->Aantal;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id,
'Wonen->Verdiepingen->Aantal');
}
// Amount of rooms
if (isset($propertyJson->Wonen->Verdiepingen->AantalKamers)) {
$property->amountOfRooms = $propertyJson->Wonen->Verdiepingen->AantalKamers;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id,
'Wonen->Verdiepingen->AantalKamers');
}
// Amount of bedrooms
if (isset($propertyJson->Wonen->Verdiepingen->AantalSlaapKamers)) {
$property->amountOfBedrooms = $propertyJson->Wonen->Verdiepingen->AantalSlaapKamers;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id,
'Wonen->Verdiepingen->AantalSlaapKamers');
}
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Wonen->Verdiepingen');
}
// Get Other Property information
// Through these we will just loop in the blade
if (isset($propertyJson->Wonen->WonenDetails)) {
$property->details = $propertyJson->Wonen->WonenDetails;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Wonen->WonenDetails');
}
if (isset($propertyJson->Wonen->Woonlagen)) {
$property->propertyFloors = $propertyJson->Wonen->Woonlagen;
}
else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Wonen->Woonlagen');
}
// Get Subtype specific data
if (isset($propertyJson->Wonen->Woonhuis)) {
$property->typeId = 1;
// Get Type Name
if (isset($propertyJson->Wonen->Woonhuis->TypeWoning)) {
$property->typeName = ucfirst($propertyJson->Wonen->Woonhuis->TypeWoning);
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id,
'Wonen->Woonhuis->TypeWoning');
}
// Get Sort Name
if (isset($propertyJson->Wonen->Woonhuis->SoortWoning)) {
$property->sortName = ucfirst($propertyJson->Wonen->Woonhuis->SoortWoning);
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id,
'Wonen->Woonhuis->SoortWoning');
}
}
elseif (isset($propertyJson->Wonen->Appartement)) {
$property->typeId = 2;
// Get Type Name
if (isset($propertyJson->Wonen->Appartement->KenmerkAppartement)) {
$property->typeName = ucfirst($propertyJson->Wonen->Appartement->KenmerkAppartement);
}
// else { // Don't log this because it can be empty
// $this->sendPropertyDataErrorMail($property->translatable->object->id,
// 'Wonen->Appartement->KenmerkAppartement');
// }
// Get Sort Name
if (isset($propertyJson->Wonen->Appartement->SoortAppartement)) {
$property->sortName = ucfirst($propertyJson->Wonen->Appartement->SoortAppartement);
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id,
'Wonen->Appartement->SoortAppartement');
}
// Get Apartment Floor
if (isset($propertyJson->Wonen->Appartement->Woonlaag)) {
$property->apartmentFloor = $propertyJson->Wonen->Appartement->Woonlaag;
}
// else { // Don't log this because it can be empty
// $this->sendPropertyDataErrorMail($property->translatable->object->id,
// 'Wonen->Appartement->Woonlaag');
// }
}// When Subtype is used that isn't defined send message
else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Wonen->{Type}', 3);
}
}
// Property also can be a lot
elseif (isset($propertyJson->Bouwgrond)) {
// Get Property information
if (isset($propertyJson->Bouwgrond->HuidigeBestemming)) {
$property->destination = $propertyJson->Bouwgrond->HuidigeBestemming;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Bouwgrond->HuidigeBestemming');
}
if (isset($propertyJson->Bouwgrond->HuidigGebruik)) {
$property->currentUse = $propertyJson->Bouwgrond->HuidigGebruik;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Bouwgrond->HuidigGebruik');
}
if (isset($propertyJson->Bouwgrond->Bouwrijp)) {
$property->constructReady = $propertyJson->Bouwgrond->Bouwrijp;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Bouwgrond->Bouwrijp');
}
if (isset($propertyJson->Bouwgrond->Liggingen) && isset($propertyJson->Bouwgrond->Liggingen->Ligging)) {
$positionString = [];
if(count($propertyJson->Bouwgrond->Liggingen) > 1) {
foreach ($propertyJson->Bouwgrond->Liggingen->Ligging as $key => $positionString) {
if($key !== 0) $positionString .= ', ';
$positionString .= $positionString;
}
} else {
$positionString = $propertyJson->Bouwgrond->Liggingen->Ligging;
}
$property->position = $positionString;
}else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Bouwgrond->Liggingen{->Ligging}');
}
}
else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, 'Wonen|Bouwgrond');
}
}
}
private function bindMediaToProperty(&$property)
{
// Define the public path of the property
$publicPath = $property->translatable->object->public_path;
// Check if realworks folder for property exists
if (file_exists(public_path($publicPath))) {
$folders = scandir(public_path($publicPath)); // Get files in folder in ascending order
$folders = array_diff($folders, ['..', '.']); // Remove Up or Down directors of Linux
$folders = array_values($folders); // Reset array to only values
$media = [];
// Loop through the folders
foreach ($folders as $folder) {
if (file_exists(public_path($publicPath . $folder))) {
// Change naming to English if needed
switch ($folder) {
case ('HoofdFoto'):
$folderName = 'headerImage';
break;
case ('Foto'):
$folderName = 'images';
break;
case ('Plattegrond'):
$folderName = 'map';
break;
default:
$folderName = strtolower($folder);
break;
}
$media[$folderName] = [];
// Find files inside folder
$files = scandir(public_path($publicPath . $folder)); // Get files in folder in ascending order
$files = array_diff($files, ['..', '.']); // Remove Up or Down directors of Linux
$files = array_values($files); // Reset array to only values
foreach ($files as $file) {
// For the file location we don't need the public path because they should be based upon the root of the site instead of server
$src = $publicPath . $folder . '/' . $file;
// For images we grab the width, height
if (in_array($folderName, ['images', 'headerImage'])) {
/*
* Try to get the image size an images
* On error skip this file
*/
try
{
/*
* 0 = width
* 1 = height
*/
$imageSize = getimagesize(public_path($src));
$media[$folderName][] = (object)[
'src' => $src,
'width' => $imageSize[0],
'height' => $imageSize[1],
];
}
catch(\Exception $e)
{
\Log::warning('Error getimagesize on path: '.$src);
}
}else {
$media[$folderName][] = $src;
}
}
}
}
$property->media = (object)$media;
} // Send error mail for not finding realworks folder
else {
$this->sendPropertyDataErrorMail($property->translatable->object->id, $publicPath);
}
}
private function getLongAndLatOfProperty(&$property){
// Generate geocoding string
$geocodingUrlString = config('services.googleMaps.geocodingUrl');
$location = $property->straatnaam. ' '.$property->huisnummer.$property->huisnummer_toevoeging.', '.$property->postcode;
if($property->land == 'NL') $location .= ' Netherlands';
$geocodingUrlString .= '?address='.$location;
$geocodingUrlString .= '&key='.config('services.googleMaps.apiKeyServer');
try {
// Make geocoding request
$client = new Client();
$response = $client->get($geocodingUrlString);
// debug($geocodingUrlString);
$locationString = $response->getBody()->getContents();
// Decode json string
$locationJson = json_decode($locationString);
$results = $locationJson->results;
// Check that there are results and make the first the main
if(sizeof($results) == 0 ) return false;
$mainResult = $results[0];
// Add the received response to the model
$property->translatable->location_json = $locationString;
// Check that de data we want isset
if(isset($mainResult->geometry) && isset($mainResult->geometry->location)){
// Add the desired variables
$property->translatable->long = $mainResult->geometry->location->lng;
$property->translatable->lat = $mainResult->geometry->location->lat;
// Also bind them to the loaded property
$property->long = $mainResult->geometry->location->lng;
$property->lat = $mainResult->geometry->location->lat;
}
// Save the model
$property->translatable->save();
}
catch (\Exception $e){
debug($e->getRequest());
debug($e->getResponse());
return false;
}
}
private function sendPropertyDataErrorMail($propertyId, $dataTail, $errorType = 1, $variable = '')
{
// Don't send the mails on production
// if (\App::environment('production')) return false;
switch ($errorType) {
case (1):
$errorString = 'Not found Property Tail';
break;
case (2):
$errorString = 'Unexpected Property Variable';
break;
case (3):
$errorString = 'Not defined Property Type';
break;
case (4):
$errorString = 'No Submodel Property';
break;
default:
$errorString = 'Unknown Property Error';
break;
}
// \Mail::send('site.emails.propertyDataError', [
// 'propertyId' => $propertyId,
// 'dataTail' => $dataTail,
// 'errorType' => $errorType,
// 'errorString' => $errorString,
// 'variable' => $variable
// ], function ($message) use ($propertyId, $errorString) {
//
// $message->from(\Config::get('mail.from.address'), \Config::get('mail.from.name'));
// $message->to(\Config::get('mail.admin.address'));
//
// // Set subject
// $message->subject($errorString . ': Object id ' . $propertyId);
//
// });
}
}