From 68ff95e7febbff99d5a3e5980a043f1856d536e7 Mon Sep 17 00:00:00 2001 From: Jozef Date: Tue, 14 Nov 2017 11:16:14 +0100 Subject: [PATCH 1/2] create Trait for geoModel Very helpful when I need to use with ex. `User` class and extends `Authenticatable` or similar use case --- src/Eloquent/GeoTrait.php | 177 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/Eloquent/GeoTrait.php diff --git a/src/Eloquent/GeoTrait.php b/src/Eloquent/GeoTrait.php new file mode 100644 index 000000000..a5dd08ae0 --- /dev/null +++ b/src/Eloquent/GeoTrait.php @@ -0,0 +1,177 @@ + 'ElevenLab\PHPOGC\DataTypes\Point', + 'multipoints' => 'ElevenLab\PHPOGC\DataTypes\MultiPoints', + 'linestrings' => 'ElevenLab\PHPOGC\DataTypes\LineString', + 'multilinestrings' => 'ElevenLab\PHPOGC\DataTypes\MultiLineString', + 'polygons' => 'ElevenLab\PHPOGC\DataTypes\Polygon', + 'multipolygons' => 'ElevenLab\PHPOGC\DataTypes\MultiPolygon', + 'geometrycollection' => 'ElevenLab\PHPOGC\DataTypes\GeometryCollection' + ]; + + public $tmp_geo = []; + + /** + * Overriding the "booting" method of the model. + * + * @return void + */ + protected static function boot() + { + parent::boot(); + + static::creating(function($model){ + self::updateGeoAttributes($model); + }); + + static::created(function($model){ + self::updateGeoAttributes($model); + }); + + static::updating(function($model){ + self::updateGeoAttributes($model); + }); + + static::updated(function($model){ + self::updateGeoAttributes($model); + }); + } + + /** + * Get a new custom query builder instance for the connection. + * + * @return \Illuminate\Database\Query\Builder + */ + protected function newBaseQueryBuilder() + { + $conn = $this->getConnection(); + + $grammar = $conn->getQueryGrammar(); + + return new Builder($conn, $grammar, $conn->getPostProcessor()); + } + + /** + * @param $geotype + * @return bool + */ + private static function isValidGeotype($geotype) + { + return (in_array($geotype, array_keys(static::$geotypes))); + } + + /** + * @param $model + * @param $attribute + * @return mixed + * @throws \Exception + */ + private static function getGeoType($model, $attribute) + { + foreach ($model->geometries as $geometry => $attributes) { + if(in_array($attribute, $attributes)) + return $geometry; + } + throw new \Exception('Given attribute has no geotype.'); + } + + /** + * @param $model + * @throws \Exception + */ + public static function updateGeoAttributes($model) + { + if( ! isset($model->geometries) ) return; + + foreach($model->geometries as $geotype => $attrnames){ + if(!self::isValidGeotype($geotype)) + throw new \Exception('Unknown geotype: ' . $geotype); + + $classname = static::$geotypes[$geotype]; + + foreach ($attrnames as $attrname){ + if( isset($model->$attrname) ){ + + if($model->$attrname instanceof Expression){ + $model->setAttribute( $attrname, $model->tmp_geo[$attrname] ); + unset($model->tmp_geo[$attrname]); + + }else if($model->$attrname instanceof $classname){ + $model->tmp_geo[$attrname] = $model->$attrname; + $model->setAttribute( $attrname, \DB::rawGeo( $model->$attrname )); + + }else{ + throw new \Exception('Geometry attribute ' . $attrname .' must be an instance of ' . $classname); + } + } + } + } + } + + /** + * @param array $attributes + * @param null $connection + * @return \Illuminate\Database\Eloquent\Model + * @throws \Exception + */ + public function newFromBuilder($attributes = [], $connection = null) + { + $model = parent::newFromBuilder($attributes, $connection); + if( ! isset($model->geometries) ) return; + + foreach($model->geometries as $geotype => $attrnames) { + if(!self::isValidGeotype($geotype)) + throw new \Exception('Unknown geotype: ' . $geotype); + + foreach ($attrnames as $attrname) { + if (isset($model->$attrname)) { + $model->$attrname; // use the magic __get to instantiate element + } + } + } + return $model; + } + + /** + * @param string $key + * @return mixed + */ + public function __get($key) + { + if( + in_array($key, array_flatten($this->geometries)) && // if the attribute is a geometry + ! parent::__get($key) instanceof OGCObject && // if it wasn't still converted to geo object + ! parent::__get($key) instanceof Expression && // if it is not in DB Expression form + parent::__get($key) != "" // if it is not empty + ){ + $geotype = self::getGeoType($this, $key); + $classname = self::$geotypes[$geotype]; + $data = parent::__get($key); + + # here we have 3 possible value for $data: + # 1) binary: we probably have a BLOB from MySQL + # 2) hex: PgSQL gives an hex WKB output for geo data + # 3) WKT: else + # + if(!ctype_print($data) or ctype_xdigit($data)){ + $wkb = \DB::fromRawToWKB(parent::__get($key)); + $this->setAttribute($key, $classname::fromWKB($wkb)); + + }else{ // assuming that it is in WKT + $this->setAttribute($key, $classname::fromWKT($data)); + } + + } + return parent::__get($key); + } +} From 6e4cb78be6a203516ffdaac38e4ebb06c08471bc Mon Sep 17 00:00:00 2001 From: Jozef Date: Tue, 14 Nov 2017 14:54:55 +0100 Subject: [PATCH 2/2] boot trait name --- src/Eloquent/GeoTrait.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Eloquent/GeoTrait.php b/src/Eloquent/GeoTrait.php index a5dd08ae0..840885396 100644 --- a/src/Eloquent/GeoTrait.php +++ b/src/Eloquent/GeoTrait.php @@ -26,10 +26,8 @@ trait GeoTrait * * @return void */ - protected static function boot() + protected static function bootGeoTrait() { - parent::boot(); - static::creating(function($model){ self::updateGeoAttributes($model); });