Doctrine findBy 'does not equal' - doctrine-orm

How do I do
WHERE id != 1
In Doctrine?
I have this so far
$this->getDoctrine()->getRepository('MyBundle:Image')->findById(1);
But how do I do a "do not equals"?
This maybe daft, but I cannot find any reference to this?
Thanks

There is now a an approach to do this, using Doctrine's Criteria.
A full example can be seen in How to use a findBy method with comparative criteria, but a brief answer follows.
use \Doctrine\Common\Collections\Criteria;
// Add a not equals parameter to your criteria
$criteria = new Criteria();
$criteria->where(Criteria::expr()->neq('prize', 200));
// Find all from the repository matching your criteria
$result = $entityRepository->matching($criteria);

There is no built-in method that allows what you intend to do.
You have to add a method to your repository, like this:
public function getWhatYouWant()
{
$qb = $this->createQueryBuilder('u');
$qb->where('u.id != :identifier')
->setParameter('identifier', 1);
return $qb->getQuery()
->getResult();
}
Hope this helps.

To give a little more flexibility I would add the next function to my repository:
public function findByNot($field, $value)
{
$qb = $this->createQueryBuilder('a');
$qb->where($qb->expr()->not($qb->expr()->eq('a.'.$field, '?1')));
$qb->setParameter(1, $value);
return $qb->getQuery()
->getResult();
}
Then, I could call it in my controller like this:
$this->getDoctrine()->getRepository('MyBundle:Image')->findByNot('id', 1);

Based on the answer from Luis, you can do something more like the default findBy method.
First, create a default repository class that is going to be used by all your entities.
/* $config is the entity manager configuration object. */
$config->setDefaultRepositoryClassName( 'MyCompany\Repository' );
Or you can edit this in config.yml
doctrine:
orm:
default_repository_class: MyCompany\Repository
Then:
<?php
namespace MyCompany;
use Doctrine\ORM\EntityRepository;
class Repository extends EntityRepository {
public function findByNot( array $criteria, array $orderBy = null, $limit = null, $offset = null )
{
$qb = $this->getEntityManager()->createQueryBuilder();
$expr = $this->getEntityManager()->getExpressionBuilder();
$qb->select( 'entity' )
->from( $this->getEntityName(), 'entity' );
foreach ( $criteria as $field => $value ) {
// IF INTEGER neq, IF NOT notLike
if($this->getEntityManager()->getClassMetadata($this->getEntityName())->getFieldMapping($field)["type"]=="integer") {
$qb->andWhere( $expr->neq( 'entity.' . $field, $value ) );
} else {
$qb->andWhere( $expr->notLike( 'entity.' . $field, $qb->expr()->literal($value) ) );
}
}
if ( $orderBy ) {
foreach ( $orderBy as $field => $order ) {
$qb->addOrderBy( 'entity.' . $field, $order );
}
}
if ( $limit )
$qb->setMaxResults( $limit );
if ( $offset )
$qb->setFirstResult( $offset );
return $qb->getQuery()
->getResult();
}
}
The usage is the same than the findBy method, example:
$entityManager->getRepository( 'MyRepo' )->findByNot(
array( 'status' => Status::STATUS_DISABLED )
);

I solved this rather easily (without adding a method) so i'll share:
use Doctrine\Common\Collections\Criteria;
$repository->matching( Criteria::create()->where( Criteria::expr()->neq('id', 1) ) );
By the way, i'm using the Doctrine ORM module from within Zend Framework 2 and i'm not sure whether this would be compatible in any other case.
In my case, i was using a form element configuration like this: to show all roles except "guest" in a radio button array.
$this->add([
'type' => 'DoctrineModule\Form\Element\ObjectRadio',
'name' => 'roles',
'options' => [
'label' => _('Roles'),
'object_manager' => $this->getEntityManager(),
'target_class' => 'Application\Entity\Role',
'property' => 'roleId',
'find_method' => [
'name' => 'matching',
'params' => [
'criteria' => Criteria::create()->where(
Criteria::expr()->neq('roleId', 'guest')
)
],
],
],
]);

I used the QueryBuilder to get the data,
$query=$this->dm->createQueryBuilder('AppBundle:DocumentName')
->field('fieldName')->notEqual(null);
$data=$query->getQuery()->execute();

Related

using Cakephp Restful WS with primary key different from default 'id'

I want to create a Webservice in cakephp but the primary key is not id_supp but taken the default value id
this is the modal:
<?php
App::uses('AppModel', 'Model');
class Supplier extends AppModel {
var $primaryKey = 'id_supp';
this is the route
Router::mapResources(array('suppliers'));
and this is the view action
public function view($id) {
$supplier = $this->Supplier->findById($id);
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
The result when accessing the following url via GET
/suppliers/54f4dc83-0bd0-4fdd-ab8b-0a08ba3b5702.json
is:
{
"code": 500,
"url": "\/TN\/Back_rest\/suppliers\/54f4dc83-0bd0-4fdd-ab8b-0a08ba3b5702.json",
"name": "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Supplier.id' in 'where clause'",
"error": {
"errorInfo": [
"42S22",
1054,
"Unknown column 'Supplier.id' in 'where clause'"
],
"queryString": "SELECT `Supplier`.`id_supp`, `Supplier`.`company_name`, `Supplier`.`contact_name`, `Supplier`.`contact_title`, `Supplier`.`address`, `Supplier`.`postcode`, `Supplier`.`phone`, `Supplier`.`fax`, `Supplier`.`www`, `Supplier`.`active`, `Supplier`.`created`, `Supplier`.`modified` FROM `tn`.`suppliers` AS `Supplier` WHERE `Supplier`.`id` = '54f4dc83-0bd0-4fdd-ab8b-0a08ba3b5702' LIMIT 1"
}}
Because cakephp uses convention over configuration you should use id for your table primary id field. In your example you could find what you are looking for like this:
public function view($id = null) {
$supplier = $this->Supplier->find('first', array(
'conditions' => array(
'Supplier.id_supp' => $id
)
));
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
or like this:
public function view($id = null) {
$this->Supplier->primaryKey = $id;
$supplier = $this->Supplier->find('first');
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
or like this:
public function view($id = null) {
$supplier = $this->Supplier->findByIdSupp($id);
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
Choose what ever pleases you the most.

Doctrine validate-schema PDOexception

When I do this step on marco pivetta tutorial
Validate-schema
I have this error :
[PDOException]
SQLSTATE[HY000] [1045] Access denied for user 'username'#'localhost' (using password: YES)
The problem is, on line command i think my doctrine.local.php
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'driverClass' =>'Doctrine\DBAL\Driver\PDOMySql\Driver',
'params' => array(
'host' => 'localhost',
'port' => '3306',
'user' => 'root',
'password' => '',
'dbname' => 'test',
'charset' => 'utf8',
'driverOptions' => array (1002 => 'SET NAMES utf8'),
)
)
)
)
);
is not loaded for this tool. My $params is empty (Doctrine\DBAL\Driver\PDOMySql\Driver) And _constructPdoDsn return standard $dsn, not my configs params.
My Os is windows 7
I'm working with Zend Framework2 on wamp
and I use Console2 with gitBash for command line.
I'm stuck any help please ?
You need to have cli-config.php in your root.
Here is content of mine:
<?php
date_default_timezone_set('Europe/Prague');
use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
chdir(__DIR__);
class Bootstrap
{
protected static $serviceManager;
protected static $config;
protected static $bootstrap;
public static function init()
{
// Load the user-defined test configuration file, if it exists; otherwise, load
if (is_readable(__DIR__ . '/config/application.config.php')) {
$testConfig = include __DIR__ . '/config/application.config.php';
} else {
//$testConfig = include __DIR__ . '/TestConfig.php.dist';
}
$zf2ModulePaths = array();
if (isset($testConfig['module_listener_options']['module_paths'])) {
$modulePaths = $testConfig['module_listener_options']['module_paths'];
foreach ($modulePaths as $modulePath) {
if (($path = static::findParentPath($modulePath)) ) {
$zf2ModulePaths[] = $path;
}
}
}
$zf2ModulePaths = implode(PATH_SEPARATOR, $zf2ModulePaths) . PATH_SEPARATOR;
$zf2ModulePaths .= getenv('ZF2_MODULES_TEST_PATHS') ?: (defined('ZF2_MODULES_TEST_PATHS') ? ZF2_MODULES_TEST_PATHS : '');
static::initAutoloader();
// use ModuleManager to load this module and it's dependencies
$baseConfig = array(
'module_listener_options' => array(
'module_paths' => explode(PATH_SEPARATOR, $zf2ModulePaths),
),
);
$config = ArrayUtils::merge($baseConfig, $testConfig);
$serviceManager = new ServiceManager(new ServiceManagerConfig());
$serviceManager->setService('ApplicationConfig', $config);
$serviceManager->get('ModuleManager')->loadModules();
\Doctrine\ORM\Tools\Console\ConsoleRunner::run(
new \Symfony\Component\Console\Helper\HelperSet(
array(
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($serviceManager->get('Doctrine\ORM\EntityManager'))
)
)
);
static::$serviceManager = $serviceManager;
static::$config = $config;
}
public static function getServiceManager()
{
return static::$serviceManager;
}
public static function getConfig()
{
return static::$config;
}
protected static function initAutoloader()
{
$vendorPath = static::findParentPath('vendor');
if (is_readable($vendorPath . '/autoload.php')) {
$loader = include $vendorPath . '/autoload.php';
} else {
$zf2Path = getenv('ZF2_PATH') ?: (defined('ZF2_PATH') ? ZF2_PATH : (is_dir($vendorPath . '/ZF2/library') ? $vendorPath . '/ZF2/library' : false));
if (!$zf2Path) {
throw new RuntimeException('Unable to load ZF2. Run `php composer.phar install` or define a ZF2_PATH environment variable.');
}
include $zf2Path . '/Zend/Loader/AutoloaderFactory.php';
}
AutoloaderFactory::factory(array(
'Zend\Loader\StandardAutoloader' => array(
'autoregister_zf' => true,
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/' . __NAMESPACE__,
),
),
));
}
protected static function findParentPath($path)
{
$dir = __DIR__;
$previousDir = '.';
while (!is_dir($dir . '/' . $path)) {
$dir = dirname($dir);
if ($previousDir === $dir) return false;
$previousDir = $dir;
}
return $dir . '/' . $path;
}
}
Bootstrap::init();
I found solution....
On windows seven, we have to use this line command (or we can also do this command via index.php in public dir since zf2 2.3.0)
vendor/bin/doctrine-module orm:validate-schema
And, if you use gitBash don't forget if you have tested your APPLICATION_ENV variable in application.config.php like this tutorial
Zf2 advances config setup
do in bash_profile file :
export APPLICATION_ENV="development"
Hope this help someone.
You don't need to have cli-config.php in the root directory to do that.

Drupal services endpoint returns 404 : Could not find resource retrieve

I followed this tutorial :
http://pingv.com/blog/an-introduction-drupal-7-restful-services
and seems everyone have the same problem as mine in the comments.
I made a rest service with drupal services module :
Server = REST
path = api/mohtadoon
mohtadoon_api.module file
<?php
/**
* Implements of hook_services_resources().
*/
function mohtadoon_api_services_resources() {
$api = array(
'mohtadoon' => array(
'operations' => array(
'retrieve' => array(
'help' => 'Retrieves mohtadoon data',
'callback' => 'mohtadoon_api_stories_retrieve',
'file' => array('file' => 'inc', 'module' => 'mohtadoon_api','name' => 'resources/mohtadoon_api'),
'access arguments' => array('access content'),
),
),
),
);
return $api;
}
mohtadoon_api.inc file in resources/mohtadoon_api path
<?php
function mohtadoon_api_stories_retrieve() {
return mohtadoon_api_find_stories();
}
function mohtadoon_api_find_stories() {
// Compose query
$query = db_select('node', 'n');
$query->join('node_revision', 'v', '(n.nid = v.nid) AND (n.vid = v.vid)');
$query->join('users', 'u', 'n.uid = u.uid');
$query->join('field_data_body', 'b', '((b.entity_type = \'node\') AND (b.entity_id = n.nid) AND (b.revision_id = n.vid))');
$query->fields('v', array('timestamp', 'title'));
$query->addField('u', 'name', 'author');
$query->addField('b', 'body_value', 'content');
$query->condition('n.type', 'stories', '=');
$items = $query->execute()->fetchAll();
return $items;
}
?>
when I access the path
http://localhost/mohtadoon01/?q=api/mohtadoon/retrieve
where mohtadoon01 is project path AND ?q= because
the request result is 404 Not found: Could not find resource retrieve.
why is this happens && how to debug something like this ... I didn't deal with drupal before and want to make only one get web service.
You likely need to url encode your string:
http://localhost/mohtadoon01/?q=api%2Fmohtadoon%2Fretrieve
Can't promise this will work though, depending on your drupal configuration.
Slashes are allowed in query string, as per RFC: http://ietf.org/rfc/rfc3986.txt, however many services out of the box do not: you may need to enable AllowEncodedSlashes.
I encountered exactly the same thing using Services 7.x-3.7. To understand the issue, I looked through the following file:
services/servers/rest_server/includes/RESTServer.inc
Given the definition of your service, the code exercised by GET requests for your resource should be:
protected function resolveController($resource, &$operation) {
...
if ( $request_method == 'GET'
&& $canon_path_count >= 1
&& isset($resource['operations']['retrieve'])
&& $this->checkNumberOfArguments($canon_path_count, $resource['operations']['retrieve'])
&& !empty($canonical_path_array[0])
) {
$operation_type = 'operations';
$operation = 'retrieve';
}
...
}
If we now take a look at the code for $this->checkNumberOfArguments():
// We can see from the snippet above that $args_number = $canon_path_count and hence that
// $args_number is always greater than 0
protected function checkNumberOfArguments($args_number, $resource_operation, $required_args = 0) {
$not_required_args = 0;
if (isset($resource_operation['args'])) {
foreach ($resource_operation['args'] as $argument) {
if (isset($argument['source']) && is_array($argument['source']) && isset($argument['source']['path'])) {
if (!empty($argument['optional'])) {
$not_required_args++;
}
else {
$required_args++;
}
}
}
}
// This is where we fall down; Since the service definition does not include any args,
// both $required_args and $not_required_args will equal zero when we get here. Not a problem
// for the first condition (1 >= 0), but clearly the second condition (1 <= 0 + 0) will evaluate
// to false and hence the argument count will not be accepted. As a result, the services module
// does not accept this controller and reports this as '404 not found'
return $args_number >= $required_args && $args_number <= $required_args + $not_required_args;
}
Try adding an argument to your service definition like this:
<?php
/**
* Implements of hook_services_resources().
*/
function mohtadoon_api_services_resources() {
$api = array(
'mohtadoon' => array(
'operations' => array(
'retrieve' => array(
'help' => 'Retrieves mohtadoon data',
'callback' => 'mohtadoon_api_stories_retrieve',
'file' => array('file' => 'inc', 'module' => 'mohtadoon_api','name' => 'resources/mohtadoon_api'),
'access arguments' => array('access content'),
'arg' => array(
array(
'name' => 'entity',
'type' => 'string',
'description' => 'Entity to operate on',
'source' => array('path' => '0'),
'optional' => TRUE,
'default' => '0',
),
),
),
),
),
);
return $api;
}
EDIT:
I think what is confusing people reading the blog post that you linked to (and I was one of those!) is that the URL given as the accessor for the service includes as its final parameter the name of the method that it was intended to invoke ('retrieve'). You could replace 'retrieve' with pretty much anything and the service should still respond (e.g. '/api/blog/pink-rabbit' or, in your case, 'api/mohtadoon/pink-rabbit'). The web service definitions themselves do not indicate what value of parameters can be passed to the endpoint. What counts is what HTTP method is used to access the service and how many parameters are passed to the endpoint (zero or more). Some types of operation require at least a certain number of parameters (e.g. 'retrieve' operations require at least one parameter to identify the specific thing that you want to retrieve).

phpunit mock expectation failed for method name is equal

I have the following subject to test:
class ReportTable_Renderer_Html_Decorator_AddRecord extends ReportTable_Renderer_Html_Decorator_CallParent
{
public function renderAddItem(ReportTable $table)
{
$newRow = array();
$masterIDColumn = $this->getMasterIDColumn();
if (!empty($masterIDColumn)) {
$newRow[$masterIDColumn] = $this->getOwner()->getMasterID();
}
foreach ($table->getColumns() as $name => $column) {
$newRow[$name] = '';
}
$newRow['id'] = '0';
if (!empty($newRow[$masterIDColumn])) $newRow['id'] .= '_' . $newRow[$masterIDColumn];
$newRow[$this->getColumn()] = $this->getText();
$this->getRowStyle()->getGroupStyles()->add('do_not_print grey');
return $this->getParent()->renderRowContent($table, $newRow);
}
and also this (indirect) parent class, whose functions I need to stub for the test
class ReportTable_Renderer_Html_Decorator_Base extends ReportTable_Renderer_Html
{
public function renderRowContent(ReportTable $table, array $row) {}
public function renderRowSetFooter(ReportTable $table) {}
}
My test:
public function testRenderRowSetFooter()
{
$table = new ReportTable('a','b');
$table->addColumn( new ReportTable_Column( 'one', 'one' ));
$table->addColumn( new ReportTable_Column( 'two', 'two' ));
$table->addColumn( new ReportTable_Column( 'three', 'three' ));
$testText = 'test text';
$parentFooterText = 'parent.parent';
$groupID = 234;
$addText = 'Add me. Add me now!';
$newRow = array('one' => $addText, 'two' => $groupID, 'three' => '', 'id' => 0 );
$parent = $this->getMock('ReportTable_Renderer_Html_Base', array( 'renderRowContent', 'renderRowSetFooter' ));
$parent->expects($this->any())->method('renderRowContent')->with($table, $newRow)->will($this->returnValue($testText));
$parent->expects($this->any())->method('renderRowSetFooter')->with($table)->will($this->returnValue($parentFooterText));
$subject = $this->getSubject($parent, array( 'text' => $addText, 'column' => 'one', 'masterIDColumn' => 'two' ));
$subject->getOwner()->setMasterID($groupID);
$this->assertEquals($parentFooterText . $testText, $subject->renderRowSetFooter($table));
}
I'm stuck with this error message which happens for both mocked functions:
PHPUnit_Framework_ExpectationFailedException : Expectation failed for method name is equal to <string:renderRowContent> when invoked zero or more times
Parameter 1 for invocation Herkt_ReportTable_Renderer_Html_Base::renderRowContent(Herkt_ReportTable Object (...), Array (...)) does not match expected value.
Failed asserting that two arrays are equal.
One of the arrays shows is $newRow, the other one obviously the resut of the function. But I did not add an assertEquals for these arrays? How does this come about and how can I fix my test?
Ok, figured it out. I inherited this test and am adapting it to changed functionality. What happens is that because of the mock functions, the actual testing happens by passing $newRow into the mock function renderRowContent
My test failed because I didn't adapt the expected parameters to the change in my tested function
it should be:
$newRow = array(
'masterColumn' => $groupID,
'one' => $addText,
'two' => '',
'three' => '',
'id' => '0_234'
);

ZF2 - set selected value on Select Element

I've a problem with dropdown list with Zend Framework 2 & Doctrine.
I would put the "selected" attribute on my dropdown list but all options pass to selected
My code :
Controller :
public function editAction()
{
// get error message during addAction
$this->layout()->setVariable("messageError", $this->flashMessenger()->getErrorMessages());
$auth = $this->getAuthService();
if ($auth->hasIdentity()){
$builder = new AnnotationBuilder();
// Get id of StaticContent
$id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
if (!$id) {
$this->flashMessenger()->addErrorMessage("Aucun plan choisi !");
return $this->redirect()->toRoute('admin/plans');
}
$plan = $this->getEntityManager()->getRepository("Admin\Entity\Plan")->find((int)$id);
$form = $builder->createForm($plan);
// Find options for Localite list (<select>)
$localites = $this->getEntityManager()->getRepository("Admin\Entity\Localite")->getArrayOfAll();
$form->get('localiteid')->setValueOptions($localites);
$form->get('localiteid')->setValue("{$plan->getLocaliteid()->getId()}");
// Find options for TypePlan list (<select>)
$typesPlan = $this->getEntityManager()->getRepository("Admin\Entity\TypePlan")->getArrayOfAll();
$form->get('typeid')->setValueOptions($typesPlan);
$form->get('typeid')->setValue("{$plan->getTypeid()->getId()}");
// Options for Statut list (<select>)
$form->get('statut')->setValueOptions(array('projet'=>'Projet', 'valide'=>'Validé'));
$form->get('statut')->setValue($plan->getStatut());
$form->setBindOnValidate(false);
$form->bind($plan);
$form->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Modifier',
'id' => 'submitbutton',
'class' => "btn btn-primary"
),
));
$request = $this->getRequest();
if ($request->isPost()) {
[...]
}
}
With
$localites = $this->getEntityManager()->getRepository("Admin\Entity\Localite")->getArrayOfAll();
$form->get('localiteid')->setValueOptions($localites);
i populate my dropdown correctly, normally with
$form->get('localiteid')->setValue("{$plan->getLocaliteid()->getId()}");
just set "selected" on option defined by :
$plan->getLocaliteid()->getId()
So why all options are selected in my dropdown ?!
Information : It's the same for typeId but no Statut
It's probably not working because of the curly braces. According to the PHP documentation
Using single curly braces ({}) will not work for accessing the return values of functions or methods or the values of class constants or static class variables.
This is also unnecessary when using setValue. ZF2 will convert it to a string when formatting it in the view.
When you create the arrays to pass to setValueOptions() you should make it an associative array of arrays with the following values:
$form->get('select')->setValueOptions(array(
'field' => array(
'value' => 'value_of_the_option',
'label' => 'what is displayed',
'selected' => true,
),
));
Which ever of the fields has the selected option set to true will be the default selection in the form element.
Personally i don't know if getArrayOfAll() such function exists, i assume that you are correctly passing array to FORM,
I think you should be doing something like this to set value.
$form->get('localiteid')->setValue($plan->getLocaliteid()->getId());
But Since you are populating DROP down i guess this approach will not work best with Drop Down. You need to do something like this
$form->get('localiteid')->setAttributes(array('value'=>$plan->getLocaliteid()->getId(),'selected'=>true));
I've found a bug ?!
$plan = $this->getEntityManager()->getRepository("Admin\Entity\Plan")->find((int)$id);
$idLocalite = 18;//(int)$plan->getLocaliteid()->getId();
$idTypePlan = 2;//(int)$plan->getTypeid()->getId();
When i'm using $plan->getLocaliteid()->getId(); or $plan->getTypeid()->getId() to pass parameter into Repository method getArrayOfAll($idLocalite)
LocaliteRepository.php :
class LocaliteRepository extends EntityRepository {
public function getArrayOfAll($currentLocaliteId) {
$result = $this->_em->createQuery("SELECT l.nom, l.localiteid FROM Admin\Entity\Localite l ORDER BY l.nom")->getArrayResult();
$localite = array();
foreach($result as $loc) {
if ($currentLocaliteId == $loc['localiteid']) {
$localite[$loc['localiteid']] = array(
'value' => $loc['localiteid'],
'label' => $loc['nom'],
'selected' => true,
);
} else {
$localite[$loc['localiteid']] = array(
'value' => $loc['localiteid'],
'label' => $loc['nom'],
'selected' => false
);
//$localite[$loc['localiteid']] = $loc['nom'];
}
}
return $localite;
}
}
So, if i'm using $idLocalite = 18 instead of $idLocalite = (int)$plan->getLocaliteid()->getId() only wanted option are selected. Why ?!