Skip to content

Instantly share code, notes, and snippets.

@SapioBeasley
Last active November 6, 2022 12:54
Show Gist options
  • Select an option

  • Save SapioBeasley/2527381917fa32c97937 to your computer and use it in GitHub Desktop.

Select an option

Save SapioBeasley/2527381917fa32c97937 to your computer and use it in GitHub Desktop.
Rets Laravel Command

Working on a project for a client, we have decided instead of using the traditional IDX and restricting us into a box, go with RETS.

To read more on the differences between IDX and RETS feel free to view it here

Now on to the code!!

Install Depenancies

Assuming you have laravel installed already, we need one other dependancy added.

https://github.com/troydavisson/PHRETS

Add this snippet into your composer.json file

{
    "require": {
        "troydavisson/phrets": "2.*"
    }
}

composer install

If you are not at all familiar with RETS or PHRets, We strongly advise you view Troy's great information he supplies on his repo. https://github.com/troydavisson/PHRETS

Making Laravel Console Command

First at hand you must create your console command. Laravel offers a great way to stub your command by running the command php artisan make:console {commandName}. For this example we will be using

php artisan make:console rets:properties

The command above would generate a class at app/Console/Commands/rets.php

Once your command is generated, you should fill out the signature and description properties of the class, which will be used when displaying your command on the list screen.

The handle method will be called when your command is executed. You may place any command logic in this method. Once the make:console is ran you will have an example stub of your command like below.

<?php

namespace DummyNamespace;

use Illuminate\Console\Command;

class DummyClass extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'dummy:command';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

Function by Function

Start by filling in your signature. This will be the name of the command you mention in your make:console command.

/**
 * The name and signature of the console command.
 *
 * @var string
 */
 protected $signature = 'rets:properties';

Give your command a description that will be shown when running php artisan list

/**
 * The console command description.
 *
 * @var string
 */
 protected $description = 'Pull residential properties from rets and import into DB';

As mentioned previously you can set console global instances. In the constructor is where we define them. In this example we are setting our login and session setting of PHRets.

/**
 * Create a new command instance.
 *
 * @return void
 */
 public function __construct()
 {
    parent::__construct();
    
    // Instanciste PHRETS configuation
    $config = new \PHRETS\Configuration;
    
    // Request a login using our RETS creds
    $config->setLoginUrl(env('RETS_LOGIN_URL'))
        ->setUsername(env('RETS_USERNAME'))
        ->setPassword(env('RETS_PASSWORD'))
        ->setRetsVersion('1.7.2');

    // Start up a PHRETS Session with our login response
    $this->rets = new \PHRETS\Session($config);
    
    // Connect to the service
    $connect = $this->rets->Login();
}

Every call after this point will allow us to run queries on our RETS data. Now let's execute the command.

The purpose of this command was to pull in the rets data and handle it as such

  • Save each property into our database
  • Grab and download all images if the property is not closed
  • Create new communities if not already available
  • Relate a property to an available community
  • Check for closed properties and remove the images from disk.

Let us take a look. Follow the comments to understand the flow.

/**
 * Execute the console command.
 *
 * @return mixed
 */
 public function handle()
 {
    // Search for all properties available
    $results = $this->rets->Search('Property', '1', '*', [
        'Limit' => 500,
        'StandardNames' => 0, // give system names
    ]);
    
    // Rename returned number keys as names
    $results = $this->fieldRename($results);

    // For each property returned
    foreach ($results as $property) {
        
        // Check if the property already exists in the database
        $createdProperty = \App\Property::where('listingID', '=', $property['listingID'])->with('propertyImages')->first();
        
        // If the property exists, updated it else create a new property
        switch (true) {
            case ! is_null($createdProperty):

                $createProperty = $createdProperty->update($property);
                
                // Check listing status, if its closed do not add images
                if ($createdProperty->listingStatus == 'Closed') {
                    
                    // If property is closed and has images, delete them from the database and disk
                    if (! empty($createdProperty->propertyImages->toArray())) {
                        $closedImages = $createdProperty->propertyImages;

                        $this->removeClosedImages($closedImages);
                        $this->info('Closed listing images removed');
                    }

                }
                
                // Print to the console
                $this->info('Property found and updated');
                break;

            default:
                // Create a new property
                $createProperty = \App\Property::create($property);
                $this->info('New Property Created');
                
                // Define properties community
                $community = $property['communityName'];
                
                // Make sure the property has a community listed
                if ($community !== 'None') {
                    
                    // Check if community is already saved
                    $createdCommunity = \App\Community::where('community', '=', $community)->first();

                    if (is_null($createdCommunity)) {
                        
                        // Create community as a relation to the property
                        $createProperty->community()->create([
                            'community' => $community
                        ]);
                        $this->info('New Community Created');
                    } else {
                    
                        // Update the property with new community
                        $createProperty->community()->sync([$createdCommunity->id]);
                    }
                }
                
                // Check if listing is closed or not
                if ($createProperty->listingStatus !== 'Closed') {
                    
                    // Grab images listed with property
                    $images = $this->getPropertyImages($property['sysId']);
                    
                    // Create image as relation of property
                    foreach ($images as $image) {
                        $createProperty->propertyImages()->create([
                            'dataUri' => $image
                        ]);
                    }
                    $this->info('Property Images added');
                }
                break;
            }
        }
    }

    public function removeClosedImages($closedImages)
    {
        // Delete all in the array
        foreach ($closedImages as $image) {

            unlink(public_path('images/uploads/properties/') . $image->dataUri);

            $propertyImage = \App\Image::find($image->id);

            $propertyImage->delete();
        }

        return;
    }

    public function getPropertyImages($listingId)
    {
        // Grab all images associated to property with $listingId
        $photos = $this->rets->GetObject('Property', 'Photo', $listingId);
        
        // Save each image on disk
        foreach ($photos as $photo) {

            file_put_contents(public_path('images/uploads/properties/') . 'property-' . $listingId . '-image-' . $photo->getObjectId() . '.jpg', $photo->getContent());
            $images[] = 'images/uploads/properties/' . 'property-' . $listingId . '-image-' . $photo->getObjectId() . '.jpg';

        }

        return $images;
    }

    public function fieldRename($oldArray)
    {
        // For each item in the array rename the keys
        foreach ($oldArray as $arrayData) {
            $newArray[] = [
                'sysId' => $arrayData['sysid'],
                'propertyType' => $arrayData['1'],
                'approximateAcreage' => $arrayData['2'],
                'postalCode' => $arrayData['10'],
                'streetName' => $arrayData['243'],
                'streetNumber' => $arrayData['244'],
                'yearBuilt' => $arrayData['264'],
                'city' => $arrayData['2909'],
                'state' => $arrayData['2963'],
                'listPrice' => $arrayData['144'],
                'listingStatus' => $arrayData['242'],
                'originalListPrice' => $arrayData['173'],
                'listingID' => $arrayData['163'],
                'propertyDescription' => $arrayData['268'],
                'totalBaths' => $arrayData['63'],
                'lotSqft' => $arrayData['154'],
                'bedrooms' => $arrayData['68'],
                'waterHeaterDescription' => $arrayData['2932'],
                'garageDescription' => $arrayData['269'],
                'roofDescription' => $arrayData['270'],
                'lotDescription' => $arrayData['271'],
                'spaDescription' => $arrayData['272'],
                'poolDescription' => $arrayData['273'],
                'interiorDescription' => $arrayData['292'],
                'otherApplianceDescription' => $arrayData['290'],
                'constructionDescription' => $arrayData['291'],
                'flooringDescription' => $arrayData['293'],
                'fireplaceDescription' => $arrayData['294'],
                'builtDescription' => $arrayData['72'],
                'carportDescription' => $arrayData['73'],
                'parkingDescription' => $arrayData['2438'],
                '5thBedroomDescription' => $arrayData['97'],
                'heatingDescription' => $arrayData['301'],
                'greatRoomDescription' => $arrayData['2432'],
                'bathDownstairsDescription' => $arrayData['64'],
                'coolingFuelDescription' => $arrayData['86'],
                'diningRoomDescription' => $arrayData['276'],
                'familyRoomDescription' => $arrayData['277'],
                'kitchenDescription' => $arrayData['278'],
                'livingRoomDescription' => $arrayData['279'],
                'masterBedroomDescription' => $arrayData['281'],
                '2ndBedroomDescription' => $arrayData['282'],
                '3rdBedroomDescription' => $arrayData['283'],
                '4thBedroomDescription' => $arrayData['284'],
                'possessionDescription' => $arrayData['285'],
                'ovenDescription' => $arrayData['289'],
                'equestrianDescription' => $arrayData['296'],
                'miscellaneousDescription' => $arrayData['298'],
                'exteriorDescription' => $arrayData['299'],
                'landscapeDescription' => $arrayData['300'],
                'heatingFuelDescription' => $arrayData['302'],
                'energyDescription' => $arrayData['305'],
                'furnishingsDescription' => $arrayData['2426'],
                'loftDescription' => $arrayData['2539'],
                'unitDescription' => $arrayData['2543'],
                'saleType' => $arrayData['2941'],
                'idx' => $arrayData['1809'],
                'images' => $arrayData['129'],
                'photoExcluded' => $arrayData['2883'],
                'photoInstructions' => $arrayData['182'],
                'communityName' => $arrayData['155'],
            ];
        }

        return $newArray;
    }

This command is currently working as it should. Please feel free to send any recommendations to info@sapioweb.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment