PHP5 - OOP - Polymorphism - Help me to rewrite this simple switch - php

Assuming i have this classic switch, i know that when we are building classes is not a good practice use the switch method, so, how i can rebuild this into a class without using switch but Polymorphism and i would like to understand the approach.
/**
* globals below are holding unique id
* $Franklin['Franklin_id'] ,
* $Granny_Smith['Granny_Smith_id'] ,
* etc etc...
*/
global $Fuji, $Gala, $Franklin, $Granny_Smith;
switch($Apple) {
case 'Fuji':
$Color = 'Yellowish green';
$Size = 'medium';
$Origin = 'Japan';
$Season = 'October - January';
$AppleId = $Fuji['Fuji_id'];
break;
case 'Gala':
$Color = 'yellow';
$Size = 'medium';
$Origin = 'New Zealand';
$Season = 'October - January';
$AppleId = $Gala['Gala_id'];
break;
case 'Franklin':
$Color = 'Well-colored';
$Size = 'medium';
$Origin = 'Ohio';
$Season = 'October';
$AppleId = $Franklin['Franklin_id'];
break;
case 'Granny_Smith':
$Color = 'Green';
$Size = 'medium';
$Origin = 'Australia';
$Season = 'October - December';
$AppleId = $Granny_Smith['Granny_Smith_id'];
break;
}
then i would like to be able to use it something like this
$AppleProps = new getApple('Granny_Smith'); // $AppleProps->Color, etc etc
Thank you in advance and hope this can help someone else.
Kind Regards
Luca
thank's to http://www.allaboutapples.com/ for Apples Informations ;)

If you really want to use OO for this, then what you should do is create an appleFactory class, then have separate classes for each kind of apple...
class appleFactory
{
public static function getApple( $name )
{
$className = $name.'_apple';
return new $className( );
}
}
class fuji_apple
{
public function __construct( )
{
$this->color = 'Yellowish green';
$this->size = 'medium';
$this->origin = 'Japan';
$this->season = 'October - January';
$this->appleId = $Fuji['Fuji_id'];
}
}
class gala_apple
{
public function __construct( )
{
$this->color = 'Yellow';
$this->size = 'medium';
$this->origin = 'New Zealand';
$this->season = 'October - January';
$this->appleId = $Gala['Gala_id'];
}
}
Then use it like so...
$fuji = appleFactory::get( 'fuji' );
$gala = appleFactory::get( 'gala' );

I'm not complete sure what your IDs mean, but this code gives you an AppleFactory that will "stamp" each new apple with a unique ID.
class AppleFactory {
static $id = 0;
static public function getApple($className) {
$apple = new $className();
$apple->id = self::$id++;
return $apple;
}
}
class Apple {
public $id;
public $color;
public $size;
public $origin;
public $season;
}
class GrannySmith extends Apple {
public function __construct() {
$this->color = 'Green';
$this->size = 'medium';
$this->origin = 'Australia';
$this->season = 'October - Desember';
}
}
$a = AppleFactory::getApple('GrannySmith');
print_r($a);

There's no need for object-orientation here. But the switch can be replaced by a much simpler construct. If you use a data array, you can even skip the function:
$apple_data = array(
'Fuji' => array(
'Color' => 'Yellowish green';
'Size' => 'medium';
'Origin' => 'Japan';
'Season' => 'October - January';
'AppleId' = 1234567890,
),
'Gala' => array(
'Color' => 'yellow';
'Size' => 'medium';
'Origin' => 'New Zealand';
'Season' => 'October - January';
'AppleId' => 1234598760,
),
...
);
To access the attributes just use:
$id = $apple_data["Granny_Smith"]["AppleId"]
Or if you really want all those local variables:
extract($apple_data["Granny_Smith"]);
// creates $Color, $Size, $Origin, $Season, $AppleId in local scope
If you really want the object-syntax, then try:
$AppleProps = new ArrayObject($apple_data["Fuji"], 2);
print $AppleProps->Color;
But since the apples are not doing anything, you probably don't want to create a class or real objects for them. (Damn apples. Just sitting there and doing nothing.)

Related

Problem of Curly Brackets in my controller Php Symfony

I want to call my function but when I call it I have a problem with curly Brackets at the end of my code and i have this error Error SYMFONY ( {} ) in my Controller.
I have no idea where to put them for my code to work. I have this problem when I add my function that allows me to retrieve the
history of the action. The mentioned function goes as this:
$this->logHistory->addHistoryConnection($project->getId(), $user->getId(), 'Delete Local Suf', $sf_code);
Function Supp Suf
/**
* #Route("/creation/suf/supp", name="suf_supp")
*/
public function suf(
Request $request,
ShapesRepository $shapesRepository
) {
$params = $this->requestStack->getSession();
$projet = $params->get('projet');
$modules = $params->get('modules');
$fonctionnalites = $params->get('fonctionnalites');
$user = $this->getUser()->getUserEntity();
$manager = $this->graceManager;
$mapManager = $this->mapManager;
$countElements = $mapManager->getCount();
$shapes = $shapesRepository->findBy(array('projet' => $projet->getId()));
$adresseWeb = $this->getParameter('adresse_web');
$carto = $params->get('paramCarto');
$centrage = $params->get('centrage');
$cableColor = $params->get('cableColor');
$sf_code = '';
if ($request->get('suf') != '') {
$sf_code = $request->get('suf');
}
$suf = $manager->getSuf($sf_code);
$success = '';
$error = '';
$warning = '';
if ($request->query->get('success')) {
$success = $request->query->get('success');
} elseif ($request->query->get('error')) {
$error = $request->query->get('error');
} elseif ($request->query->get('warning')) {
$warning = $request->query->get('warning');
}
if ($request->isMethod('POST')) {
if ($request->request->get('sf_code') != '') {
$sf_code = $request->request->get('sf_code');
}
if ($request->get('val') != '') {
$val = $request->get('val');
}
$dir = $this->getparameter('client_directory');
$dossier = str_replace(' ', '_', $projet->getProjet());
$dir = $dir . $dossier . '/documents/';
$cable = $val[0];
$chem = $val[1];
$t_suf = $this->graceCreator->supprimeSuf($sf_code, $cable, $chem);
if ($t_suf[0][0] == '00000') {
$this->logHistorique->addHistoryConnection($projet->getId(), $user->getId(), 'Suppression Suf Local', $sf_code);
// $creator->delDirObjet( $st_code, $dir );
$data = new JsonResponse(array("success" => "create!"));
return $data;
} else {
$data = new JsonResponse(array("error" => "Error : " . $t_suf));
return $data;
}
return $this->render('Modifications/supSuf.html.twig', array(
'user' => $user,
'paramCarto' => $carto,
'cableColor' => $cableColor,
'suf' => $suf,
'adresseWeb' => $adresseWeb,
'centrage' => $centrage,
'shapes' => $shapes,
'projet' => $projet,
'modules' => $modules,
'fonctionnalites' => $fonctionnalites,
'countElements' => $countElements
));
}
}
Your only return statement is inside of an if condition. If the code does not pass the condition, it has nothing to return. The code must return something in all possible cases. If you are not still used to these practices, an IDE might guide you until it becomes a routine. PHPStorm is my personal preference.
BTW, I recommend you to switch from the array() syntax to the more globally accepted [] although you must be in PHP 5.4 or higher.

PHPSpreadsheet generates empty file if it containts more than 16 rows

I am generating a xlsx file with PHPspreadshet and it always gives me an empty file (0kb) when it has more than 16 rows. I already tried to search for erros etc. and found nothing. It just depends on the row.
The Spreadsheet (Html for testing):
And when I switch following lines:
$this->sheet->setCellValue("A16", "Besetzt");
To
$this->sheet->setCellValue("A17", "Besetzt");
The generator (execute() is the entry point):
class ExcelOperation extends AbstractOperation
{
private function addWork($cell, $name = "", $phone = ""){
if($cell != null){
$richText = new \PhpOffice\PhpSpreadsheet\RichText\RichText();
$boldText = $richText->createText($name);
//$boldText->getFont()->setBold(true);
$richText->createText("\n".$phone);
$this->sheet->getCell($cell)->setValue($richText);
$this->sheet->getStyle($cell)->getAlignment()->setWrapText(true);
$this->sheet->getStyle($cell)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
}
}
public function execute(WebRequest $wreq, WebResponse $wres){
$eventId = $wreq->getParameter();
$userId = "1839357067871549236";
$calendar = $this->getCalendar($userId, $eventId);
$eventStatistics = $this->getEventStatistics($eventId);
//All Positions
$this->renderPositionData($calendar);
//$this->renderCurrentStatus($eventStatistics);
$this->formatColumn("A");
$this->formatColumn("B");
$this->formatColumn("C");
$this->formatColumn("D");
//$writer = new Xlsx($this->spreadsheet);
$writer = new Html($this->spreadsheet);
$wres->success(true);
$wres->set("filename", "Schichtplan.html");
$wres->set("file", $writer->save('php://output'));
}
private function addFullBorder($from, $to){
/*$styleArray = array(
'borders' => array(
'outline' => array(
'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
'color' => array('argb' => PhpOffice\PhpSpreadsheet\Style\Color::COLOR_BLACK),
),
),
);
$this->sheet ->getStyle($from.':'.$to)->applyFromArray($styleArray);*/
}
private function renderCurrentStatus($statistics){
$this->sheet->setCellValue("F2", "Stand");
$this->sheet->mergeCells('F2:G2');
$this->sheet->getStyle("F2")->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
$this->sheet->getStyle("F2")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID);
$this->sheet->getStyle("F2")->getFill()->getStartColor()->setRGB("A4DDF5");
$this->sheet->getStyle("F2")->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE);
$frei = $statistics["gesamt"]-($statistics["warten"]+$statistics["besetzt"]);
$this->sheet->setCellValue("F2", "Frei");
$this->sheet->setCellValue("G2", $frei);
$this->sheet->setCellValue("F4", "Besetzt");
$this->sheet->setCellValue("G4", $statistics["besetzt"]);
$this->sheet->setCellValue("F6", "Wartend");
$this->sheet->setCellValue("G6", $statistics["warten"]);
$this->sheet->setCellValue("F8", "Gesamt");
$this->sheet->setCellValue("G8", $statistics["gesamt"]);
$this->addFullBorder("F2", "G8");
}
private function renderPositionData($calendar){
foreach($calendar as $positionId => $position){
$positionName = $position["position"]["alle_positionen_description"];
preg_match('/Pos\. [0-9]+/', $positionName, $matches);
$positionEndCell = null;
$actualCol = $this->positionCount%$this->positionsPerLine;
if(isset($matches[0])){
$shortPositionName = $matches[0];
}else{
$shortPositionName = $positionName;
}
if($actualCol <5){
$cell = $this->getCell($actualCol, $this->actualRowPerPosition);
//var_dump($cell);
//For Position header
$this->actualRowPerPosition[$actualCol] += 1;
$this->addPositionHeader($cell, $shortPositionName);
$positionStartCell = $cell;
//All shifts within this job
foreach($position["jobs"] as $job){
//For Each Shift in Position
$cell = $this->getCell($actualCol, $this->actualRowPerPosition);
//$cell = "A17";
//var_dump($cell);
$this->sheet->setCellValue("A17", "Besetzt");
$formattedDateFrom = $this->dbDateToTime($job["job"]["alle_schichten_start"]);
$formattedDateTo = $this->dbDateToTime($job["job"]["alle_schichten_ende"]);
$this->addShiftHeader($cell, $formattedDateFrom." - ".$formattedDateTo);
$this->actualRowPerPosition[$actualCol] = 18;
$positionEndCell = $cell;
foreach($job["workers"] as $worker){
$fullName = $worker["firstname"]." ".$worker["secondname"];
$phone = "+43";
$cell = $this->getCell($actualCol, $this->actualRowPerPosition);
$this->addWork($cell, $fullName, $phone);
//$this->actualRowPerPosition[$actualCol] += 1;
$positionEndCell = $cell;
}
}
if($positionEndCell == null){
$positionEndCell = $positionStartCell;
}
$this->addFullBorder($positionStartCell, $positionEndCell);
$this->positionCount++;
}
}
}
private function formatColumn($columnName){
$this->sheet->getColumnDimension($columnName)->setWidth(35);
}
private function dbDateToTime(string $dateTime){
$date = new \DateTime($dateTime);
$formattedDateFrom = $date->format('H:i');
return $formattedDateFrom;
}
private function getCell($actualCol, $actualRowPerPosition){
$actualRow = $actualRowPerPosition[$actualCol]+1;
$actualColName = $this->getColName($actualCol);
$cell = $actualColName.$actualRow;
$this->sheet->getRowDimension($actualRow)->setRowHeight(30);
return $cell;
}
private function addPositionHeader($cell, $positionName){
$this->sheet->setCellValue($cell, $positionName);
//Font Color
$this->sheet->getStyle($cell)->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE);
$this->sheet->getStyle($cell)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
//Background Color
$this->sheet->getStyle($cell)->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID);
$this->sheet->getStyle($cell)->getFill()->getStartColor()->setRGB("A4DDF5");
}
private function addShiftHeader($cell, $shiftText){
$this->sheet->setCellValue($cell, $shiftText);
$this->sheet->getStyle($cell)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
}
private function getColName($colId){
$cols = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"];
return $cols[$colId];
}
private function getCalendar($userId, $eventId){
$dbManager = new DbManager();
$jobs = $dbManager->getAdminCalendarForUser($eventId, $userId);
$calendar = $this->generateCalendarArray($jobs);
return $calendar;
}
private function getEventStatistics($eventId){
$dbManager = new DbManager();
$eventStatistics = $dbManager->getEventStatistics($eventId);
return $eventStatistics;
}
private function generateCalendarArray($jobs){
$dbManager = new DbManager();
$calendar = [];
foreach ($jobs as $job) {
if(!isset($calendar[$job["alle_positionen_id"]])){
$jobFieldsWithValues = $this->getJobFieldsWithValues($dbManager, $job["alle_positionen_id"]);
$job["needs_approval"] = $job["needs_approval"] ? true : false;
$calendar[$job["alle_positionen_id"]] =
[
"position" =>$job,
"jobFieldsWithValues"=> $jobFieldsWithValues,
"jobs" => [],
"positionPermission"=>$job["positionPermission"]
];
}
//Check if position has shift
if($job["alle_schichten_id"] != null){
//Check if job in this shift (falsely defined as job) exists
if(!isset($calendar[$job["alle_positionen_id"]]["jobs"][$job["alle_schichten_id"]])){
$calendar[$job["alle_positionen_id"]]["jobs"][$job["alle_schichten_id"]] = [
"job"=>$job,
"workers"=>[]
];
}
if($job["Email"] != null){
$jobDef = [
"email"=>$job["Email"],
"approved"=>$job["Approved"],
"userId"=>$job["id"]."",
"firstname"=>$job["Vorname"],
"secondname"=>$job["Nachname"]
];
array_push($calendar[$job["alle_positionen_id"]]["jobs"][$job["alle_schichten_id"]]["workers"], $jobDef);
}
}
}
return $calendar;
}
private function getJobFieldsWithValues(DbManager $dbManager, int $positionId) : array{
$jobFieldsWithValues = [];
$jobFields = $dbManager->getJobFieldsWithValues($positionId);
foreach ($jobFields as $jobField) {
if(isset($jobFieldsWithValues[$jobField["id"]])){
array_push($jobFieldsWithValues[$jobField["id"]]["values"], ["data-value"=>$jobField["value"], "value"=>$jobField["value"]]);
}else{
$jobFieldsWithValues[$jobField["id"]] = [
"id"=>$jobField["id"],
"fieldBaseType"=>$jobField["fieldDataType"],
"name"=>$jobField["Bezeichnung"],
"description"=>$jobField["description"],
"values"=>[]];
array_push($jobFieldsWithValues[$jobField["id"]]["values"], ["data-value"=>$jobField["value"], "value"=>$jobField["value"]]);
}
}
return $jobFieldsWithValues;
}
public function __construct() {
$this->spreadsheet = new Spreadsheet();
$this->sheet = $this->spreadsheet->getActiveSheet();
$this->positionsPerLine = 4;
$this->actualRowPerPosition = [0,0,0,0];
$this->positionCount = 0;
$this->colors = [
"black"=>\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_BLACK
];
}
}
It generates an empty file.

How to differentiate filename without hardcoding it?

i have a config like so :
$CONF['log']['TSEL_MV_GW_SERV101_MT_CONNECTOR_STATUS'] = array(
'folder' => $CONF['mainFolder']."/log_sample/tsel",
'files' => array(
'connector_access_log*.log',
'engine_dr_to_app_hit_dr_url*.log'
)
);
then i'm getting all the files with that pattern that has today date.
foreach($CONF['log'] as $label => $arrayData){
$filePaths = array();
$today = date("Ymd", time());
foreach($arrayData['files'] as $filePrefix){
$glob = glob($arrayData['folder']."/".$filePrefix, GLOB_ERR);
if(count($glob) >= 1){
foreach($glob as $file){
if(strpos($file, $today)){
$filePaths[] = $file;
}
}
}
}
}
$filePaths array content :
Array
(
[0] =>/dirpath/connector_access_log_20171025.log
[1] =>/dirpath/engine_dr_to_app_hit_dr_url_20171025.log
)
Now, i need to process each file differently, how can i do this using foreach loop ?
using hardcode such as if(preg_match("connector_access_log")) is not allowed.
this is my approach before :
foreach($filePaths as $filePath){
if(preg_match("/connector_access_log_/", $filePath, $match)){
#some code
} else if (preg_match("/engine_dr_to_app_hit_dr_url_/", $filePath, $match)){
#some code
}
}
What you could do is, you could tweak the configuration to store files in assosiative array Eg.
$CONNECTOR_ACCESS_LOG = 'connector_access_log'
$ENGINE_URL_LOG = 'engine_dr_to_app_hit_dr_url'
$CONF['log']['TSEL_MV_GW_SERV101_MT_CONNECTOR_STATUS'] = array(
'folder' => $CONF['mainFolder']."/log_sample/tsel",
'files' => array(
$CONNECTOR_ACCESS_LOG => 'connector_access_log*.log',
$ENGINE_URL_LOG => 'engine_dr_to_app_hit_dr_url*.log'
)
);
And then in the loop you can get these keys and switch case between them. Eg.
foreach($CONF['log'] as $label => $arrayData){
$today = date("Ymd", time());
foreach($arrayData['files'] as $filetype => $filePrefix){
$glob = glob($arrayData['folder']."/".$filePrefix, GLOB_ERR);
if(count($glob) >= 1){
foreach($glob as $file){
if(strpos($file, $today)){
switch($filetype) {
case $CONNECTOR_ACCESS_LOG: doConnection($file); break;
case $ENGINE_URL_LOG : doEngine($file); break;
}
}
}
}
}
}
Please pardon my php syntax, i am just trying to give an idea.
If you really don't want to use a hardcode you should pass a handler for each file type through your config. Like mostly frameworks do. Please see yii2 logger for more examples. Here is a piece of pseudocode:
$CONF['log']['TSEL_MV_GW_SERV101_MT_CONNECTOR_STATUS'] = array(
new FirstLogger($CONF['mainFolder']."/log_sample/tsel", 'connector_access_log*.log'),
new SecondLogger($CONF['mainFolder']."/log_sample/tsel", 'engine_dr_to_app_hit_dr_url*.log'),
);
Next, proccess your log files by your handler in your handler class.
class FirstLogger
{
protected $dir = null;
protected $fileWildCard = null;
public function __construct($dir, $fileWildcard)
{
$this->dir = $dir;
$this->fileWildCard = $fileWildcard;
}
public function getFiles()
{
$filePaths = [];
$today = date("Ymd", time());
$glob = glob($this->dir."/".$this->fileWildCard, GLOB_ERR);
if(count($glob) >= 1){
foreach($glob as $file){
if(strpos($file, $today)){
$filePaths[] = $file;
}
}
}
return $filePaths;
}
public function handleLogs()
{
$files = $this->getFiles();
//some of your logic
}
}
Next, you probably want to create an interface for all of your loggers and an abstract class from which your loggers will be inherited.

Getting a fatal Error call to unidentified method Pass::_createpass()

Can someone please help. I am getting a fatal error on the following PHP script.
I am getting an error "unidentified method Pass::_createpass()" whick relates to the second last line of the code below.
<?php
$engine = Pass::start('xxxxxxxxxxxxxxxx');
$pass = $engine->createPassFromTemplate(xxxxxxxxxxxxxx);
$engine->redirectToPass($pass);
if (!function_exists('curl_init')) {
throw new Exception('Pass needs the CURL PHP extension.');
}
if (!function_exists('json_decode')) {
throw new Exception('Pass needs the JSON PHP extension.');
}
$engine = Pass::start($appKey);
$values = array(
'first' => 'John',
'last' => 'Platinum',
);
$images = array(
'thumbnail' => 'image1.jpg'
);
$pass = $engine->createPassFromTemplate(5688667418918912, $values, $images);
$passData = $engine->downloadPass($pass);
$engine->redirectToPass($pass);
class Pass
{
private $_appKey = null;
private $_endpoint = 'https://pass.center/api/v1';
private $_debug = false;
private static $_instance = null;
private static $_imageTypes = array('icon', 'logo', 'strip', 'thumbnail', 'background', 'footer');
const VERSION = '0.5';
const USER_AGENT = 'PassSDK-PHP/0.5';
public function __construct($appKey = null, $endpoint = null, $debug = false)
{
if (is_null($appKey)) {
throw new Exception('App Key required');
}
$this->_appKey = $appKey;
if ($endpoint !== null) {
$this->_endpoint = $endpoint;
}
$this->_debug = $debug;
}
public static function start($appKey = null, $endpoint = null, $debug = false)
{
if (self::$_instance == null) {
self::$_instance = new self($appKey, $endpoint, $debug);
}
return self::$_instance;
}
public function createPassFromTemplate($templateId, $values = array(), $images = array())
{
$resource = sprintf("https://xxxxxxx/api/v1/templates/names/Test/pass", $templateId);
return $this->_createPass($resource, $values, $images);
}
}
I hope someone can help me as I am not familiar with Functions PHP.
Thanks All
Rob
The function createPass is missing.
You need something like this:
/**
* Prepares the values and image for the pass and creates it
*
* #param string $resource Resource URL for the pass creation
* #param array $values Values
* #param array $images Images
* #return object Pass
*/
private function _createPass($resource, $values, $images)
{
$multipart = count($images) > 0;
if ($multipart) {
$content = array();
foreach ($images as $imageType => $image) {
$this->_addImage($image, $imageType, $content, $imageType);
}
var_dump($content);
// Write json to file for curl
$jsonPath = array_search('uri', #array_flip(stream_get_meta_data(tmpfile())));
file_put_contents($jsonPath, json_encode($values));
$content['values'] = sprintf('#%s;type=application/json', $jsonPath);
} else {
$content = $values;
}
return $this->_restCall('POST', $resource, $content, $multipart);
}
..And full script here

Why is my app running out of memory? Unsetting variables, using chunk

I have the simple app below. I'm turning off query logging in Laravel, I'm unsetting where possible, yet this function will only process about 800 records before I'm out of RAM on my 2GB Linode. I know I'm asking a lot of you guys but I can't seem to see where I'm leaking memory.
There are really only two major steps.
Step 1 - Move records from a temp table to production
class ListingMigrator
{
public function __construct($tempListing, $feed)
{
$this->tempListing = $tempListing;
$this->listing = $this->listingInstance();
$this->feed = $feed;
}
public static function migrateListing($listing, $feed)
{
$instance = new static($listing, $feed);
return $instance->migrate();
}
public function migrate()
{
$this->addExternalData();
$this->populateListing();
$this->processPhotos();
$this->deleteTempListing();
}
private function listingInstance()
{
DB::connection()->disableQueryLog();
$listing = Listing::findByMud($this->tempListing->matrix_unique_id);
return $listing ?: new Listing;
}
private function processPhotos()
{
$retsApi = new RetsFeedApi($this->feed);
/* Initialize Object */
$rets = $retsApi->findMostRecent();
$photos = $rets->getPhotosForListing($this->listing->matrix_unique_id);
foreach ($photos as $photo)
{
$uploader = new PhotoProcessor($this->listing, $photo);
$uploader->process();
}
}
private function populateListing()
{
DB::connection()->disableQueryLog();
$this->listing->fill($this->tempListing->toArray());
$this->listing->imported_at = $this->tempListing->created_at;
$this->listing->board = $this->tempListing->board;
return $this->listing->save();
}
private function addExternalData()
{
// Get Google lattitude and longitude
$googlecoords = getGoogleMapInfo($this->tempListing->FullAddress, $this->tempListing->City);
$this->listing->GoogleLat = $googlecoords['GoogleLat'];
$this->listing->GoogleLong = $googlecoords['GoogleLong'];
// Add or update the Subdivision Table (helper function)
$subdivisiondata = SubdivisionUpdate($this->tempListing->board, $this->tempListing->SubCondoName, $this->tempListing->Development);
$this->listing->SubdivisionID = $subdivisiondata['id'];
}
private function deleteTempListing()
{
return $this->tempListing->delete();
}
}
Step 2 - Download photos and reupload to Amazon S3
class PhotoProcessor
{
public function __construct(Listing $listing, $photoData)
{
$this->bucket = 'real-estate-listings';
$this->s3 = App::make('aws')->get('s3');
$this->tempFileName = 'app/storage/processing/images/retsphotoupload';
$this->photoData = $photoData;
$this->listing = $listing;
$this->photo = new RetsPhoto;
}
public function process()
{
$this->storeTempFile();
$this->storeFileInfo();
$this->buildPhoto();
$success = $this->pushToS3();
// if Result has the full URL or you want to build it, add it to $this->photo
DB::connection()->disableQueryLog();
$this->listing->photos()->save($this->photo);
$this->removeTempFile();
unset ($this->photoData);
return $success;
}
private function storeTempFile()
{
return File::put($this->tempFileName, $this->photoData['Data']) > 0;
}
private function storeFileInfo()
{
$fileInfo = getimagesize($this->tempFileName);
// Could even be its own object
$this->fileInfo = [
'width' => $fileInfo[0],
'height' => $fileInfo[1],
'mimetype' => $fileInfo['mime'],
'extension' => $this->getFileExtension($fileInfo['mime'])
];
}
private function buildPhoto()
{
$this->photo->number = $this->photoData['Object-ID']; // Storing this because it is relevant order wise
$this->photo->width = $this->fileInfo['width'];
$this->photo->height = $this->fileInfo['height'];
$this->photo->path = $this->getFilePath();
}
private function getFilePath()
{
$path = [];
if ($this->listing->City == NULL)
{
$path[] = Str::slug('No City');
}
else
{
$path[] = Str::slug($this->listing->City, $separator = '-');
}
if ($this->listing->Development == NULL)
{
$path[] = Str::slug('No Development');
}
else
{
$path[] = Str::slug($this->listing->Development, $separator = '-');
}
if ($this->listing->Subdivision == NULL)
{
$pathp[] = Str::slug('No Subdivision');
}
else
{
$path[] = Str::slug($this->listing->Subdivision, $separator = '-');
}
if ($this->listing->MLSNumber == NULL)
{
$pathp[] = Str::slug('No MLSNumber');
}
else
{
$path[] = Str::slug($this->listing->MLSNumber, $separator = '-');
}
$path[] = $this->photoData['Object-ID'].'.'.$this->fileInfo['extension'];
return strtolower(join('/', $path));
}
private function pushToS3()
{
return $this->s3->putObject([
'Bucket' => $this->bucket,
'Key' => $this->photo->path,
'ContentType'=> $this->fileInfo['mimetype'],
'SourceFile' => $this->tempFileName
]);
}
private function getFileExtension($mime)
{
// Use better algorithm than this
$ext = str_replace('image/', '', $mime);
return $ext == 'jpeg' ? 'jpg' : $ext;
}
private function removeTempFile()
{
return File::delete($this->tempFileName);
}
}
Edit to show RetsPhoto
class RetsPhoto extends Eloquent {
protected $table = 'rets_property_photos';
public function listing() {
return $this->belongsTo('Listing', 'matrix_unique_id', 'matrix_unique_id');
}
}
Edit #2: Chunk Call
This is in the app/command and the only thing in there is the fire() function below:
public function fire()
{
// Turn off query logging
DB::connection()->disableQueryLog();
$feeds = RetsFeed::where('active','=',1)->get();
foreach ($feeds as $feed)
{
$class = "TempListing{$feed->board}";
$listings = $class::orderBy('MatrixModifiedDT','desc');
$listings->chunk(50, function($listings) use($feed) {
$listings->each(function($listing) use ($feed) {
ListingMigrator::migrateListing($listing,$feed);
echo "Feed: $feed->board\r\n";
echo "SubcondoName: $listing->SubCondoName\r\n";
echo "Development: $listing->Development\r\n";
echo "\r\n";
});
});
}
}
I think I have figured it out.
Your system holds in memory all of the photo data. As witnessed by the unset ($this->photoData);
The problem is that you need to first complete the process function. Your application is not likely processing ANY photos so when you keep grabbing them from the file system you run out of memory BEFORE you even process a single one.
To Confirm this, simply grab 1 file not using the chunk method.
I am not very familar with Laravel, it could be grabbing all of the files all at once as well and eating the ram.
You can do some tracing with memory_get_usage(true) to find out exactly where the ram is getting eaten from. I would suggest analysing the fire method first.

Categories