Drupal 8 how to alter paragraph form? - drupal-8

In drupal 8, I'm using paragraph in node. It's working fine but I got stuck to alter paragraph form. I want to hide one field on base of other field value.
Please help if somebody worked it on before

I found below code helpful and fixed my problem. I hope it will be useful for others also.
function hook_inline_entity_form_entity_form_alter(&$entity_form, &$form_state) {
// $entity_form['#bundle'] paragraph machine name
if($entity_form['#entity_type'] == 'paragraph' && $entity_form['#bundle'] == 'location'){
$parents = $entity_form['#parents'];
$identifier = $parents[0].'['.implode('][', array_slice($parents, 1)).']';
$entity_form['field_dropoff_time']['#states'] = array(
'visible' => array(
'select[name="'. $identifier .'[field_camp_location_type]"]' => ['value' => 1]
),
);
$entity_form['field_pickup_time']['#states'] = array(
'visible' => array(
'select[name="'. $identifier .'[field_camp_location_type]"]' => ['value' => 1]
),
);
}
}

Related

Anyone else having trouble getting custom handlers to wrok on D8 entities?

I'm starting out with Drupal 8 and until now I have been quite impressed with all the new functionality. However, I have been trying to write my own entity and I'm running into trouble:
This is the entity definition:
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace Drupal\entitytest\Entity;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityTypeInterface;
/**
* Defines the Candidate Entity
*
* #ingroup entitytest
*
* #ContentEntityType(
* id="entitytest_AuditionCandidate",
* label=#Translation("Candidate"),
* base_table="candidate",
*
* handlers = {
* "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
* "list_builder" = "Drupal\entitytest\Entity\Controller\CandidateListBuilder",
* "form" = {
* "add" = "Drupal\Core\Entity\ContentEntityForm",
* "edit" = "Drupal\Core\Entity\ContentEntityForm",
* "delete" = "Drupal\EntityTest\Form\CandidateDeleteForm",
* },
* },
* admin_permission="administer candidates",
* entity_keys={
* "id"="id",
* "label"="lastname",
* },
* links = {
* "canonical" = "/AuditionCandidate/view/{entitytest_AuditionCandidate}",
* "edit-form" = "/AuditionCandidate/edit/{entitytest_AuditionCandidate}",
* },
* )
*/
class Candidate extends ContentEntityBase {
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields['id'] = BaseFieldDefinition::create('integer')
->setLabel(t('ID'))
->setDescription(t('The ID of the Contact entity.'))
->setReadOnly(TRUE);
$fields['lastname'] = BaseFieldDefinition::create('string')
->setLabel(t('Last Name'))
->setDescription(t('The name of the Contact entity.'))
->setSettings(array(
'default_value' => '',
'max_length' => 255,
'text_processing' => 0,
))
->setDisplayOptions('view', array(
'label' => 'above',
'type' => 'string',
'weight' => -6,
))
->setDisplayOptions('form', array(
'type' => 'string',
'weight' => -6,
))
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['firstname'] = BaseFieldDefinition::create('string')
->setLabel(t('First Name'))
->setDescription(t('The name of the Contact entity.'))
->setSettings(array(
'default_value' => '',
'max_length' => 255,
'text_processing' => 0,
))
->setDisplayOptions('view', array(
'label' => 'above',
'type' => 'string',
'weight' => -6,
))
->setDisplayOptions('form', array(
'type' => 'string',
'weight' => -6,
))
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
return $fields;
}
}
So I am trying to edit the Deleteform from this entity. I have created a file under /modules/custom/EntityTest/src/Form/CandidateFormDelete.php
The code in this file is as follows:
<?php
namespace Drupal\EntityTest\Form;
use Drupal\Core\Entity\ContentEntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
class CandidateDeleteForm extends ContentEntityConfirmFormBase {
public function getQuestion() {
return $this->t('Are you sure?');
}
public function getCancelUrl() {
return new Url('entity.entitytest_AuditionCandidate.collection');
}
public function getConfirmText() {
return $this->t('Delete');
}
}
I have also added a route for the delete form:
entity.entitytest_AuditionCandidate.delete_form:
path: 'AuditionCandidate/delete/{entitytest_AuditionCandidate}'
defaults:
_entity_form: entitytest_AuditionCandidate.delete
_title: 'Delete Candidate'
requirements:
_permission: 'administer candidates'
But when I try to open /AuditionCandidate/delete/1 I'm getting the following error message:
Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException: The "entitytest_AuditionCandidate" entity type did not specify a "delete" form class. in Drupal\Core\Entity\EntityManager->getFormObject() (line 309 of core/lib/Drupal/Core/Entity/EntityManager.php).
It just doesn't seem to make sense since I have definined a class for the deleteform.
Anyone who can see what I am missing? It's possibly just a typo but I have been staring at it for quite some time now and I just can't figure it out.
Matt.
Drupal 8 implements the PSR-4 standard for package-based PHP namespace autoloading.
In that case the name of your class file doesn't correspond to the name of the actual class used.
The file name should also be "CandidateDeleteForm.php" instead of "CandidateFormDelete"
That's the reason why you are getting that exception.
For more about that subject read:
https://www.drupal.org/node/2156625

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).

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 ?!

Doctrine findBy 'does not equal'

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();

Doctrine 2 update of more than one column?

How can I combine these two updates on the same tuple into one operation?
$q = $this->em->createQuery('update \Entity\UserEn u set u.last = :last where u.name = :name');
$q->setParameters( array(
'last' => new \DateTime($newLast),
'name' => $theUser,
));
$q->getResult();
$q = $this->em->createQuery('update \Entity\UserEn u set u.contribution = :contribution where u.name = :name');
$q->setParameters( array(
'contribution' => $this->rContributionUser($theUser),
'name' => $theUser,
));
$q->getResult();
I think one update is cheaper than 2 updates.
Use a comma to separate the two assignments:
$q = $this->em->createQuery('update \Entity\UserEn u set u.last = :last, u.contribution = :contribution where u.name = :name');
$q->setParameters( array(
'last' => new \DateTime($newLast),
'contribution' => $this->rContributionUser($theUser),
'name' => $theUser,
));
$q->getResult();