I've previously seen some methods for repositories where developers have a method for retrieving fields for preparing dropdowns inside of a form.
This is something I'd like to take advantage of with my application.
This is the logic that I would use in multiple areas of my app for multiple entities.
It's something I want, but I can't get it.
Does anyone know of somewhere I can find this logic?
I've done some research, but I have not found it yet.
But I've seen it, somewhere.
I finally came across something that helped me. I've also included a link for anyone that might be looking for something like this.
http://blog.dannyweeks.com/web-dev/repositories-in-laravel-sharing-my-base-repository
/**
* Items for select options
* #param string $data column to display in the option
* #param string $key column to be used as the value in option
* #param string $orderBy column to sort by
* #param string $sort sort direction
* #return array array with key value pairs
*/
public function getForSelect($data, $key = 'id', $orderBy = 'created_at', $sort = 'DECS')
{
return $this->model
->with($this->relationships)
->orderBy($orderBy, $sort)
->lists($data, $key);
}
Related
I am not able to order records by attribute from another entity.
I have class Employee, which has attribute $user, which points to class User, which have attribute $active.
Now I want to sort Employee by user.active and I am not able to do that. This is how I call the em:
/**
* #param Criteria $criteria
* #param array $order_by
* #param integer $limit
* #param integer $offset
* #return \Doctrine\Common\Collections\Collection
*/
public function findByCriteria($criteria, $order_by = null, $limit = null, $offset = null) {
$criteria->setFirstResult($offset);
$criteria->setMaxResults($limit);
$criteria->orderBy($order_by);
$result = $this->repository->matching($criteria);
return $result;
}
I inspected BaseEntityPersister.php and it seems like there is no implementation of such a thing. It just checks if user.active is an attribute of Employee class and throws
Doctrine\ORM\ORMException
Unrecognized field: user.active
I know I can do that via QueryBuilder and joins, but I want to make my code more reusable and Criteria seemed like a good choice.
Thank you for your advices!
EDIT:
If I use findBy, there is no problem with sorting field user.active. Should I consider this a limitation of matching method? It is sad, because I need to use Doctrine\Common\Collections\Criteria. I can use findBy with order and then use matching method to filter records, but I would rather do that on the database side.
EDIT 2:
I use Nette with Kdyby/Doctrine. Didn't know that user.active is implemented in Kdyby/doctrine and not in Doctrine directly. So I suppose this question won't be answered..
If you look at Kdyby/Doctrine, is extends the findBy capabilities by automatically detecting relations and performing join if needed as cane seen here by calling autoJoinOrderBy.
This is the reason why criteria does not support join, and Kdyby's findBy does.
If you want reusable way to build Doctrine queries, the Criteria does not help you with that, but there is QueryObject, which does the similar job and lets you reuse logical query parts, but using QueryBuilder.
It is not so well documented, but here are some resources:
Official documentation of QueryObject
Blog post with example usage
Kdyby/Doctrine autor's presentation on Doctrine and QueryObject (from slide 43)
Some more official information about QueryObjects
The examples shown here (https://parse.com/docs/relations_guide#onetomany-pointers) is in iOS and Android.
Is it possible to create a Pointer data store with PHP SDK?
I just ran into the same issue trying to make a many-to-many relation and after some trial and error I got it working by doing:
$obj = new ParseObject("ObjectClassName");
$obj->setAssociativeArray("relationFieldName", array('__type' => 'Pointer', 'className' => 'relationClassName', 'objectId' => 'relationObjId'));
For example, if you want to relate a Book with a User via the Book's authors key, ObjectClassName would be Book, relationFieldName would be authors and relationClassName would be _User (remember Parse's special classes are prefixed with an underscore).
Let me know if this works for you too! It's a bit frustrating that I couldn't find anything about this on Parse's PHP documentation on relations. I had the same issue in JS before but at least this question helped me right away.
I had the same issue. There is a function in the SDK specifically for this that is more concise.
In \Parse\ParseOject:
$pointer = ParseObject::create('className', $id, true);
I found it in ParseObject.php :
/**
* Static method which returns a new Parse Object for a given class
* Optionally creates a pointer object if the objectId is provided.
*
* #param string $className Class Name for data on Parse.
* #param string $objectId Unique identifier for existing object.
* #param bool $isPointer If the object is a pointer.
*
* #return ParseObject
*/
public static function create($className, $objectId = null, $isPointer = false)
It sounds like you are trying to create a 1-many relationship. You can do this using ParseObject::getRelation, which will return an existing relation, or, create a new one (you can check out the definition here).
$obj = new ParseObject("ObjectClassName");
// get a relation (new or existing)
$relation = $obj->getRelation('myObjects');
// add objects to this relation
$relation->add([$myObject1, $myObject2, $myObject3]);
// save my object & my relation, with the new objects in it
$obj->save();
If you're trying to do many-many relations you'll want to create a Join table (technically a join 'class', like MyParseJoinClass) instead. If I misunderstood, and you're trying to perform a 1-1, you can always set an object as a property to automatically create a pointer
$obj->set('myPointer', $myPointedObject);
Internally you can use $obj->_toPointer to get an array composing a pointer referencing an object, but I would recommend you utilize the supported relation & pointer types in ParseObject instead, much easier to manage.
Is it possible to apply the remember(60) function to something like Service::all()?
This is a data set that will rarely change. I've attempted several variations with no success:
Service::all()->remember(60);
Service::all()->remember(60)->get();
(Service::all())->remember(60);
Of course, I am aware of other caching methods available, but I prefer the cleanliness of this method if available.
Yes, you should be able to simply swap the two such as
Change
Service::get()->remember(60);
to
Service::remember(60)->get();
An odd quirk I agree, but after I ran into this a few weeks back and realized all I had to do was put remember($time_to_remember) in front of the rest of the query builder it works like a charm.
For your perusing pleasure: See the Laravel 4 Query Builder Docs Here
/**
* Indicate that the query results should be cached.
*
* #param int $minutes
* #param string $key
* #return \Illuminate\Database\Query\Builder
*/
public function remember($minutes, $key = null)
{
list($this->cacheMinutes, $this->cacheKey) = array($minutes, $key);
return $this;
}
L4 Docs - Queries
Here is the use case. Some fields on the document are serializable/deserializable, others don't(see #JMS\ReadOnly).
/**
* #JMS\Groups({"board_list", "board_details"})
* #JMS\Type("string")
* #MongoDB\string
*/
protected $slug;
/**
* #JMS\Groups({"board_list", "board_details"})
* #JMS\ReadOnly
* #MongoDB\Increment
*/
protected $views;
When in the controller I do an action to update the document:
/**
* [PUT] /boards/{slug} "put_board"
* #ParamConverter("board", converter="fos_rest.request_body")
* #Rest\Put("/boards/{slug}")
* #Rest\View(statusCode=204)
*/
public function putBoardAction($slug, Board $board)
{
$dm = $this->get('doctrine_mongodb')->getManager();
$board = $dm->merge($board);
$dm->flush();
return true;
}
If the views field had some value before the action, after the action it gets reset to 0. How to avoid it? Is there a work-around Merge or Persist?
If the $views property is read-only, and not set upon deserialization, it will be 0 at the time the action is invoked. When merging, ODM is first going to try to look up the Board document by its identifier. When it finds it in the database, its $views property will be the current value stored in the database. That document now becomes the managed copy that merge() will ultimately return. From there, we proceed to copy values from the Board document passed to merge(). In doing so, $views is set to 0, over-writing whatever positive number it may have stored. When ODM goes to flush this change, it calculates the differences between the new and original values (likely the original view count multiplied by -1) and uses that for an $inc. That update brings the database value back to zero.
My advice would be to issue a separate update to increment $views, perhaps using the query builder. Even if $views was not read-only for the JMS Serializer service, you could still inadvertently decrement the counter if a Board with $views less than the corresponding database value was sent into the API.
I am currently learning Symfony and Doctrine by reading the docs.
I don't understand the difference between find and findOneById. I tried to use them both in this simple example and it looks they do the same thing to me.
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:ProductEntity')
->findOneById($id);
Are they really the same thing or there is some difference? And where I can find the detailed documentation for all these methods?
In your case, they happen to do the same thing. Looking at this example, you'll notice that find() looks for the field named after the primary key. findOneBy<Field>() will explicitly use the field in the name of the method, even if it's not the primary key, and will return the first record. So, in the end, if the primary key is indeed named id, then both will do the same thing.
// query by the primary key (usually "id")
$product = $repository->find($id);
// dynamic method names to find based on a column value
$product = $repository->findOneById($id);
$product = $repository->findOneByName('foo');
There is an API here I don't think there is any difference: the two methods, when call the way you call them, do this:
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
But find will be quicker and far quicker in some cases, because it doesn't use the __call magic method, and because find() checks a map of the current unit of work before whereas load() doesn't (see the #todo):
/**
* Loads an entity by a list of field criteria.
* ...
*
* #todo Check identity map? loadById method? Try to guess whether $criteria is the id?
*/
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0)
So prefer find(), findOneById() is just a less efficient method to do the same thing.
In fact, is not the same thing.
Think about it. If you call "findBy()" you assume you'll receive a collection of entities ( 0, 1 or more than one ). So, to get all results, you'll need to iterate ArrayCollection or just get first ( $result->first() ).
If your query is by a unique key ( As this case ), you can just get unique entity by calling "getOneById()" and you will receive the entity as result.
/**
* Retrieving Product with 'findOneBy'
*/
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:ProductEntity')
->findOneById($id);
/**
* Retrieving Product with 'findBy'
*/
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:ProductEntity')
->findById($id)
->first();
Semantically, the first one it the best.
*TIP
Entity should be called just Product.
Why? Because is under "/Entity" folder ( Almost, should... ), and namespace will contain info about "What is exactly Product"
// query by the primary key (usually "id")
$product = $repository->find($id);
// dynamic method names to find based on a column value
$product = $repository->findOneById($id);
// $foo is any name which you want to find from database
$product = $repository->findOneByName($foo);
It calls the same method in the end.
findByKey('value')
Is basically the same as
findBy(array('key' => 'value'))
Where key is the property of the entity and value is the value of the property.
findById($id)
Is a special case of the above. And so is
find($id)
All of these methods execute the same query in the end. However, there is a difference in
findBy()
and
findOneBy()
Where findOneBy() only returns a single result and findBy will return all the results satisfying the demands.
However, in general it is considered good practice to use DQL queries instead. Consider lazy loading, array hydration, prepared statements, etc.
This is an interesting article on the topic:
Some Doctrine 2 Best Practices
Is the same thing, but I prefer the findOneBy method. It's more clear.