Reputation: 19
I have first entity called "places" that maps places data like place name,latitude and longitude. Another entity called "users" stores the user data like username,user current latitude,user current longitude.
I want to add a virtual field for the "places" entity that calculate the distance between the geo points.
I'm using this function -
class Places{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
* @ORM\Column(name="name", type="string", length=255)
* @Assert\NotBlank()
* @Expose
*/
private $name;
/**
* @var string
* @ORM\Column(name="description", type="string", length=255, nullable=true)
* @Expose
*/
private $description;
/**
* @var float
* @ORM\Column(name="lon", type="float", nullable=true)
* @Expose
*/
private $lon;
/**
* @var float
* @ORM\Column(name="lat", type="float", nullable=true)
* @Expose
*/
private $lat;
/**
* @var integer
* @ORM\ManyToOne(targetEntity="Countries")
* @ORM\JoinColumn(name="country", referencedColumnName="id", onDelete="SET NULL")
* @Assert\NotBlank()
* @Expose
*/
private $country;
/**
* @var string
* @VirtualProperty
* @Type("string")
* @SerializedName("distance")
* @return string
*/
public function distance(){
$longitude1 = '34.7722';//$user->getLon();(?)
$latitude1 = '32.0114';//$user->getLat();(?)
$longitude2 = $this->getLon();
$latitude2 = $this->getLat();
$theta = $longitude1 - $longitude2;
$miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$miles = acos($miles);
$miles = rad2deg($miles);
$miles = $miles * 60 * 1.1515;
$kilometers = $miles * 1.609344;
//return round($kilometers);
return $this->user->getLastName();
}
}
but as you can see the lon1/lat1 are hard coded because i can't get the user lan/lat from with in the places entity.
How do i do it?
Thanks.
Upvotes: 0
Views: 5253
Reputation: 699
You can pass $place
entity to your function:
public function distance($place)
{
$longitude1 = $place->getLon();
$latitude1 = $place->getLat();
$longitude2 = $this->getLon();
$latitude2 = $this->getLat();
$theta = $longitude1 - $longitude2;
$miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$miles = acos($miles);
$miles = rad2deg($miles);
$miles = $miles * 60 * 1.1515;
$kilometers = $miles * 1.609344;
return round($kilometers);
}
Upvotes: 1
Reputation: 236
you do not have any relations between place and user, you cant do that inside place entity. Assuming that user is the logged user. Your logic has to be in a service and inject TokenStorage to get the user logged:
namespace Acme\Bundle\AcmeBundle\Manager;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Acme\Bundle\AcmeBundle\Entity\Location;
class LocationFinder{
/*
* @var TokenStorageInterface
*/
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function getDistance(Location $location)
{
$longitude1 =$this->tokenStorage->getToken()->getUser()->getLon();
$latitude1 = $this->tokenStorage->getToken()->getUser()->getLat();
$longitude2 = $this->getLon();
$latitude2 = $this->getLat();
$theta = $longitude1 - $longitude2;
$miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$miles = acos($miles);
$miles = rad2deg($miles);
$miles = $miles * 60 * 1.1515;
$kilometers = $miles * 1.609344;
return round($kilometers);
}
}
Then you have to create the service inside Resources\config\services.xml
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="acme.manager.location_finder" class="Acme\Bundle\AcmeBundle\Manager\LocationFinder">
<argument type="service" id="security.token_storage" />
</service>
</services>
</container>
now you can get the LocationService inside a controller and get the distance between place and the user logged
class AccountController extends Controller
{
/**
* @Route("/place/{id}", name="place")
* @Method("GET")
*/
public function placeAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$location = $em->getRepository('AcmeBundle:Location')->findOneBy([
'id' => $id
]);
$distance = $this->get('acme.manager.location_finder')->getDistance($location);
}
}
You have more information here: http://symfony.com/doc/current/book/service_container.html
Sf2 : using a service inside an entity
Upvotes: 0
Reputation: 19
I got it!! Managed to solve this problem using an event listener .
listener:
class SearchIndexer{
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function postLoad (LifecycleEventArgs $args){
$entity = $args->getEntity();
if ($entity instanceof Places) {
$user = $this->tokenStorage->getToken()->getUser();
$entity->setUser_longitude($user->getLastGeoLocationLon());
$entity->setUser_latitude($user->getLastGeoLocationLat());
}
}
}
services:
services:
doctrine.listener:
class: ApplicationBundle\Listener\SearchIndexer
arguments: ["@security.token_storage"]
tags:
- { name: doctrine.event_listener, event: postLoad }
places entity:
class Places
{
private $user_longitude;
public function setUser_longitude($user_longitude){
$this->user_longitude = $user_longitude;
}
private $user_latitude;
public function setUser_latitude($user_latitude){
$this->user_latitude = $user_latitude;
}
/**
* @var string
* @VirtualProperty
* @Type("string")
* @SerializedName("distance")
* @return string
*/
public function distance(){
$longitude2 = $this->getLon();
$latitude2 = $this->getLat();
$theta = $this->user_longitude - $longitude2;
$miles = (sin(deg2rad($this->user_latitude)) * sin(deg2rad($latitude2))) + (cos(deg2rad($this->user_latitude)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
$miles = acos($miles);
$miles = rad2deg($miles);
$miles = $miles * 60 * 1.1515;
$kilometers = $miles * 1.609344;
return round($kilometers);
}
//rest of the class
}
Upvotes: 1