I've been successful in creating an extra table in the prestashop products table throught rest api of webservice , however the api link http://127.0.0.1/prestashop/api/wb3d/1 wb3d is the new table which I have created in webservice . Which holds a path to an images directory somewhere on the web . This link when opened shows the data which has been saved in the database as seen in the following image below
model is directory name on the web, so this api(wb3d) has been associated with the product table in the webservice the link:http://127.0.0.1/prestashop/api/products/1 when I open this link . The entry of the association is shown but the data is not shown **refer the below image **
The highlighted area shows the wb3d table associated with the product table throught rest api of webservice . I'm unable to associate the wb3d tale data with product table data. So I can use it in other devices through webservice
This is what I have tried so far
<?php
class ProductMergeCore extends ObjectModel
{
public $product_id;
public $id_wb3d;
public $directory_name;
public static $definition = array(
'table' => 'wb3d',
'primary' => 'id_wb3d',
'fields' => array(
'id_wb3d' => array('type' => self::TYPE_INT, 'required' => true),
'product_id' => array('type' => self::TYPE_INT, 'required' => true),
'directory_name' => array('type' => self::TYPE_STRING, 'required' =>false, 'size' => 64),
),
);
protected $webserviceParameters = array();
}
?>
productmerge.php is responsible for creating an associate table entry in product table.
<?php
Class Product extends ProductCore
{
public $extrafield;
public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, Context $context = null)
{
$this->webserviceParameters['associations']['wb3d'] = array('resource' => 'wb3d','fields' => array('directory_name' => array('required' => true)));
parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
}
}
?>
In this product.php which is for overriding the product class for passing the extra parameters through webserviceparameters() and then calling the parent constructor of the product class
<?php
class WebserviceRequest extends WebserviceRequestCore
{
public static function getResources()
{
$resources=parent::getResources();
$resources['wb3d'] = array('description' => 'images path', 'class' => 'ProductMerge');
ksort($resources);
return $resources;
}
}
?>
WebserviceRequest.php class is a override class for the WebserviceRequest class which shows the description of the table entry in the webservice
These are the files which are required to get the things done. What I'm trying to achieve is the associated table (wb3d) data should be available within the products table through webservice rest api call.
if u want to add other webservice table as your association to your product , you can take a look at how associations is done in category.php located in prestashop/classes.
'associations' => array(
'categories' => array('getter' => 'getChildrenWs', 'resource' => 'category', )
)
as you can see there is a parameter named getter which gets the value from
getChildrenWs which is a method in category.php which fetches the data from database.
so in your case: in Product.php
$this->webserviceParameters['associations']['wb3d'] = array('resource' => 'wb3d',
'getter' => 'yourMethodName',
'fields' => array('directory_name' => array('required' => true));
and create a method named 'yourMethodName' in Product.php
public function yourMethodName()
{
//copy the getChildrenWs method which is in Category.php and alter it to ur needs
}
Related
I have the following situation: Contacts without a first or last name, in fact, they only have a email address.
I can work with these contacts fine, but when I use the listview anywhere (for instance to show all contacts from a company) there now is no way to click through to the contact (normally you would click on the name).
I'm looking for a way to solve this, for instance by showing a clickable text like 'name not known', but can't figure out how to do this. I've been looking at the manual and in the files in the modules directory and the sugarfields dir, but can't quite figure it out.
The closest I got was in /sugarcrm/modules/Contacts/metadata/listviewdefs.php
where this piece of code resides:
$listViewDefs['Contacts'] = array(
'NAME' => array(
'width' => '20%',
'label' => 'LBL_LIST_NAME',
'link' => true,
'contextMenu' => array('objectType' => 'sugarPerson',
'metaData' => array('contact_id' => '{$ID}',
'module' => 'Contacts',
'return_action' => 'ListView',
'contact_name' => '{$FULL_NAME}',
'parent_id' => '{$ACCOUNT_ID}',
'parent_name' => '{$ACCOUNT_NAME}',
'return_module' => 'Contacts',
'return_action' => 'ListView',
'parent_type' => 'Account',
'notes_parent_type' => 'Account')
),
'orderBy' => 'name',
'default' => true,
'related_fields' => array('first_name', 'last_name', 'salutation', 'account_name', 'account_id'),
),
Somewhere there has to be a function that joins the first and lastname together...
Edit: I found a solution:
The actual concatenation function is in /sugarcrm/include/SugarObjects/templates/person/person.php and is called _create_proper_name_field()
I can modify the output for my specific case by adding something like this to the end of the function:
if (empty(trim($full_name))){
$full_name = 'Name unknown';
}
However, I would rather have a upgrade safe solution, so that will be the next challenge.
Don't edit the core because the next upgrade will break your SugarCRM instance. Use logic hooks to be upgrade safe:
create a file 'logic_hooks.php' in /custom/modules/Contacts/
In that file, add the followin code:
<?php
$hook_array['before_save'][] = Array(1,'logic_fill_name','custom/modules/Contacts/logic_hooks/logics.php','ContactLogics','logic_fill_name');
After you have done this. create the file 'logics.php' in /custom/modules/Contacts/logic_hooks.
In the logics.php file, add something like:
<?php
require_once 'include/SugarQuery/SugarQuery.php';
/**
* Class ContactLogics
*/
class ContactLogics {
/**
* #param $bean
* #param $event
* #param $arguments
*/
public function logic_fill_name($bean, $event, $arguments) {
if (empty(trim($bean->first_name)) && empty(trim($bean->last_name))){
$bean->last_name = 'Name unknown';
}
}
}
Now some explanation. When you edited a recordview and pressed the save button, the logic hook 'before_save' will be triggered. This code will change the full name to 'Name unknown' when the full name is empty. When the 'before_save' is executed, the actual save will take place.
I am using Doctrine 2 in my Zend Framework 2 Project. I have now created a Form and create one of my Dropdowns with Values from the Database. My Problem now is that I want to change which values are used and not the one which I get back from my repository. Okay, here some Code for a better understanding:
$this->add(
array(
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'name' => 'county',
'options' => array(
'object_manager' => $this->getObjectManager(),
'label' => 'County',
'target_class' => 'Advert\Entity\Geolocation',
'property' => 'county',
'is_method' => true,
'empty_option' => '--- select county ---',
'value_options'=> function($targetEntity) {
$values = array($targetEntity->getCounty() => $targetEntity->getCounty());
return $values;
},
'find_method' => array(
'name' => 'getCounties',
),
),
'allow_empty' => true,
'required' => false,
'attributes' => array(
'id' => 'county',
'multiple' => false,
)
)
);
I want to set the value for my Select to be the County Name and not the ID. I thought that I would need the 'value_options' which needs an array. I tried it like above, but get the
Error Message: Argument 1 passed to Zend\Form\Element\Select::setValueOptions() must be of the type array, object given
Is this possible at all?
I was going to suggest modifying your code, although after checking the ObjectSelect code i'm surprised that (as far as I can tell) this isn't actually possible without extending the class. This is because the value is always generated from the id.
I create all form elements using factories (without the ObjectSelect), especially complex ones that require varied lists.
Alternative solution
First create a new method in the Repository that returns the correct array. This will allow you to reuse that same method should you need it anywhere else (not just for forms!).
class FooRepository extends Repository
{
public function getCounties()
{
// normal method unchanged, returns a collection
// of counties
}
public function getCountiesAsArrayKeyedByCountyName()
{
$counties = array();
foreach($this->getCounties() as $county) {
$counties[$county->getName()] = $county->getName();
}
return $counties;
}
}
Next create a custom select factory that will set the value options for you.
namespace MyModule\Form\Element;
use Zend\Form\Element\Select;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
class CountiesByNameSelectFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $formElementManager)
{
$element = new Select;
$element->setValueOptions($this->loadValueOptions($formElementManager));
// set other select options etc
$element->setName('foo')
->setOptions(array('foo' => 'bar'));
return $element;
}
protected function loadValueOptions(ServiceLocatorInterface $formElementManager)
{
$serviceManager = $formElementManager->getServiceLocator();
$repository = $serviceManager->get('DoctrineObjectManager')->getRepository('Foo/Entity/Bar');
return $repository->getCountiesAsArrayKeyedByCountyName();
}
}
Register the new element with the service manager by adding a new entry in Module.php or module.config.php.
// Module.php
public function getFormElementConfig()
{
return array(
'factories' => array(
'MyModule\Form\Element\CountiesByNameSelect'
=> 'MyModule\Form\Element\CountiesByNameSelectFactory',
),
);
}
Lastly change the form and remove your current select element and add the new one (use the name that you registered with the service manager as the type key)
$this->add(array(
'name' => 'counties',
'type' => 'MyModule\Form\Element\CountiesByNameSelect',
));
It might seem like a lot more code (because it is) however you will benefit from it being a much clearer separation of concerns and you can now reuse the element on multiple forms and only need to configure it in one place.
I want to create a dropdown unique to the users, and found a way to do that, but its not ok with the client.
here is what i`ve done:
public function __construct($name = null, EntityManager $em = null, $userId = null)
{
parent::__construct($name);
$this->setAttribute('method', 'post');
[...]
$this->add(array(
'name' => 'religionId',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'object_manager' => $this->getEntityManager(),
'target_class' => 'Religions\Entity\Religions',
'property' => 'name',
'disable_inarray_validator' => true,
'by_reference' => false,
'is_method' => true,
'find_method' => array(
'name' => 'findBy',
'params' => array(
'criteria' => array('reUserId' => $userId),
'orderBy' => array('name' => 'ASC'),
),
),
),
'attributes' => array(
'multiple' => false,
'required' => false,
)
));
}
This worked, as i was sending the variable reuserId when initializing the form, using $this->identity()
The client wants to inject the user entity and select from there....
Searched stackoverflow and google, but was not able to find anything...any help please? thanks!
To 'inject' anything in ZF2 you will need to use the ServiceManager and create service factories.
It is therefore important to ensure that you are always creating the form via the ServiceManager.
In a controller for instance:
$form = $this->getServiceLocator()->get('MyModule\Form\FooForm');
Then you would need to 'inject' the user buy creating a factory class or closure.
Module.php
public function getFormElementConfig() {
return array(
'factories' => array(
'MyModule\Form\FooForm' => function($fem) {
$serviceManager = $fem->getServiceLocator();
$entityManager = $serviceManager->get('objectmanager'); // Doctrine object manager
// Load the user
// Example is the zfcUser authentication service, however replace
// this with whatever you use to maintain the users id
$user = $serviceManager->get('zfcuser_auth_service')->getIdentity();
// Inject the user entity into the form constructor
$form = new FooForm($user);
return $form;
},
),
);
}
With that said I think you might need to think about the form dependencies. It seems to me that you do not depend on the user entity - but rather the user's id should be used in a database query that reduces the list of 'Religions'.
You could execute this query and then pass the result (The religion collection) to the form in the same way my example shows how to for the user entity - This would then mean you could use a 'normal' Zend\Form\Element\Select rather than the ObjectSelect - meaning no need to inject the ObjectManager etc.
I have one controller for invoices and another for clients.
I have made some "relationships" in the models of these controllers as below:
Client.php
<?php
class Client extends AppModel {
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
'foreignKey' => 'client_id'
)
);
}
?>
Invoice.php
<?php
class Invoice extends AppModel {
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id'
)
);
}
?>
So I thought that making a drop down with each client would be easy. Although, I can't figure out how to do this.
First off this is what I want as a result:
<select>
<option value="1">Client Name</option>
</select>
Where value is equal to id in client table and Client Name is equal to name in client table.
I tried placing the following into the invoices controleler:
$client = $this->Client->find('all');
and then the following into my view:
echo $this->Form->select('client_name',client, array(
'class' => 'form-control',
'name' => 'client_id'
));
But I received the following error:
Call to a member function find() on a non-object
Directly on page load. What do I need to do to make this work?
More than likely, your problem is that the Client model is not automatically loaded in the Invoices controller. Since Client has a relationship with Invoice, you can call find on Client like this instead:
$data = $this->Invoice->Client->find('list', array('fields' => array('id', 'name')));
$this->set('clients', $data);
Then in the view,
echo $this->Form->select('Invoice.client_id', $clients);
or
echo $this->Form->input('Invoice.client_id', array('type' => 'select', 'options' => $clients));
This should output a dropdown where the values are the client id's and the visible options in the drop down are the client names. You will want to go by id's rather than client names when associating invoices with the clients.
im using Drupal 7 and I want to add a new filter in views.
I have a custom table "clicks" with two fields; nid and clicks_left.
The filter should just contain a checkbox "Only display nodes with clicks left". So the filter should join node and clicks on nid..
I have read like thousands of pages of custom filters but can't get it to work =)
Please, could someone show me a working example so I understand?
I have come so far that the filter is displayed under filters but what do I need to add to do the join and get the checkbox? The relevant code below:
FILE clicks_views.inc:
function clicks_views_data() {
$data = array();
$data['clicks']['clicks_filter'] = array(
'group' => t('Clicks'),
'title' => t('Clicks left'),
'help' => t('Filter any Views based on clicks left'),
'filter' => array(
'field' => 'clicks_left',
'handler' => 'clicks_handler_filter',
),
);
return $data;
}
FILE clicks_handler_filter.inc:
<?php
class clicks_handler_filter extends views_handler_filter {
???
};
I know both functions are wrong ;)
Ok, I've found a solution. For anyone who needs it:
In clicks.module
function clicks_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'clicks') . '/includes'
);
}
In clicks.views.inc
function clicks_views_handlers() {
return array(
'info' => array(
'path' => drupal_get_path('module', 'clicks') . '/includes', // path to view files
),
'handlers' => array(
// register our custom filter, with the class/file name and parent class
'clicks_handler_filter' => array(
'parent' => 'views_handler_filter',
)
),
);
}
function clicks_views_data() {
$data = array();
if(module_exists('clicks')) {
$data['node']['clicks'] = array(
'group' => t('Clicks'),
'title' => t('Clicks left'),
'help' => t('Filter any Views based on clicks left'),
'filter' => array(
'handler' => 'clicks_handler_filter',
),
);
}
return $data;
}
In clicks_handler_filter.inc
class clicks_handler_filter extends views_handler_filter {
function admin_summary() { }
function operator_form() { }
function query() {
$table = $this->ensure_my_table();
$join = new views_join();
$join->construct('clicks', $this->table_alias, 'nid', 'nid');
$this->query->ensure_table('clicks', $this->relationship, $join);
$this->query->add_where($this->options['group'], "clicks.clicks_left", 0, ">");
}
}
This gives me a possibility to add a filter "clicks" that if enabled hides all results that doesn't have clicks left (clicks_left > 0)
Actually, if your values in your tables clicks are numeric you don't need to create your own handler, you can use the default from Views views_handler_filter_numeric.
You can see all handlers that already exists in the Views handlers.