/**
  * Finds objects by a set of criteria.
  *
  * Optionally sorting and limiting details can be passed. An implementation may throw
  * an UnexpectedValueException if certain values of the sorting or limiting details are
  * not supported.
  *
  * @param array      $criteria
  * @param array|null $orderBy
  * @param int|null   $limit
  * @param int|null   $offset
  * @param string     $fetchPlan
  *
  * @return ArrayCollection The objects.
  * @throws OrientDBException
  */
 public function findBy(array $criteria, array $orderBy = [], $limit = null, $offset = null, $fetchPlan = '*:0')
 {
     $parts[] = sprintf('SELECT FROM %s', $this->metadata->getOrientClass());
     if ($criteria) {
         $where = [];
         foreach ($criteria as $key => $value) {
             $value = json_encode($value);
             $where[] = "{$key} = {$value}";
         }
         $parts[] = sprintf('WHERE %s', implode(' AND ', $where));
     }
     if ($orderBy) {
         $orders = [];
         foreach ($orderBy as $key => $order) {
             $orders[] = "{$key} {$order}";
         }
         $parts[] = sprintf('ORDER BY %s', implode(', ', $orders));
     }
     if ($limit) {
         $parts[] = "LIMIT " . $limit;
     }
     $select = implode(' ', $parts);
     $collection = $this->dm->query($select, $fetchPlan);
     if (!$collection instanceof ArrayCollection) {
         throw new OrientDBException("Problems executing the query \"{$select}\". " . "The server returned {$collection} instead of ArrayCollection.");
     }
     return $collection;
 }