Error: Call to undefined method MongoDB\Collection::getMongoCollection() - mongodb

I've upgraded an app from PHP74 to 81 and doctrine/mongodb-odm 1.x to 2.x.
A call to this method
private function getLoginsForPipeline(array $pipeline)
{
$collection = $dm->getDocumentCollection(LoginTrackerModel::class)->getMongoCollection();
return $collection->aggregateCursor($pipeline, ["allowDiskUse" => true]);
}
where $pipeline is defined as:-
$pipeline = [
[0] =>
array(1) {
'$sort' =>
array(1) {
'date' =>
int(-1)
}
}
[1] =>
array(1) {
'$group' =>
array(2) {
'_id' =>
string(5) "$user"
'lastLoginDate' =>
array(1) {
...
}
}
}
[2] =>
array(1) {
'$match' =>
array(1) {
'lastLoginDate' =>
array(1) {
...
}
}
}
];
returns:-
Error: Call to undefined method MongoDB\Collection::getMongoCollection()
So, looks like getMongoCollection() has been deprecated in doctrine/mongodb-odm 2.x
I have a hunch we can replace
$collection = $dm->getDocumentCollection(LoginTrackerModel::class)->getMongoCollection();
with:-
$builder = $dm->createAggregationBuilder(LoginTrackerModel::class); in 2.x
does anyone know how/what we'd replace
$collection->aggregateCursor($pipeline, ["allowDiskUse" => true]);
with in 2.x?
Am I on the right track with something along the lines of:-
$builder
->match()
->field('lastLoginDate')
->group()
->sort('date');
$result = $builder->getAggregation();
I'm not 100% since getAggregation() != aggregateCursor()

Related

is it possible to return different models in an API response

This is my first time posting here so please pardon my errors:
I have a search functionality whose route is:
Route::get('/search', 'SearchController#index');
Currently, I have an eloquent relationship where products has many deals. is it possible to return a single level deep array doing the following:
If the product has an active deal, return the deal only;
Otherwise, return the product itself.
here's what I earlier implemented in my Product.php:
public function deals()
{
return $this->hasMany(Deal::class, 'product_id');
}
Deal.php
public function product()
{
return $this->hasOne(Product::class, 'id', 'product_id');
}
SearchController:
public function index(Request $request)
{
$per_page = $request->per_page ?? 10;
$products = Product::query()->latest()
->when($request->query('filter'), function ($query) use ($request) {
$query->with('deals')->where('title', 'LIKE', "%$request->filter%");
})
->when($request->query('category'), function ($query) use ($request) {
$query->with('deals')->whereHas('categories', function ($q) use ($request) {
$q->where('title', 'LIKE', "%$request->category%");
});
})
->paginate($per_page);
return new PaginatedCollection($products, ProductResource::class);
}
and in my ProductResource:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
public function toArray($request)
{
$details = array_filter($this->details ?: [], function ($d) {
return $d != "";
});
$personalizedOptions = array_filter($this->personalized_options ?: [], function ($o) {
return $o != "";
});
return [
'id' => $this->id,
'createdAt' => $this->created_at,
'updatedAt' => $this->updated_at,
'title' => $this->title,
'sellerId' => $this->sellerId,
'description' => $this->description,
'categories' => CategoryResource::collection($this->categories),
'details' => $details,
'active' => (bool) $this->active,
'defaultPreviewImageId' => $this->default_preview_image_id,
'originalPrice' => $this->originalPrice,
'shippingPrice' => $this->shippingPrice,
'shippingWeightLbs' => $this->shippingWeightLbs,
'shippingWeightOz' => $this->shippingWeightOz,
'shippingMaxDays' => $this->shipping_max_days,
'shippingMinDays' => $this->shipping_min_days,
'personalized' => (bool) $this->personalized,
'personalizedOptions' => $personalizedOptions,
'deals' => $this->deals ?? null,
'options' => ProductOptionResource::collection($this->productOptions),
'images' => ImageResource::collection($this->images->whereNull('meta')),
'preview' => new ImageResource($this->images->where('meta', '=', 'preview')->first()),
];
}
}
Now, I have refactored the ProductResource to this but it's all returning null response
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
public function toArray($request)
{
$details = array_filter($this->details ?: [], function ($d) {
return $d != "";
});
$personalizedOptions = array_filter($this->personalized_options ?: [], function ($o) {
return $o != "";
});
if($this->deals){
DealResource::collection($this->deals);
}else{
return [
'id' => $this->id,
'createdAt' => $this->created_at,
'updatedAt' => $this->updated_at,
'title' => $this->title,
'sellerId' => $this->sellerId,
'description' => $this->description,
'categories' => CategoryResource::collection($this->categories),
'details' => $details,
'active' => (bool) $this->active,
'defaultPreviewImageId' => $this->default_preview_image_id,
'originalPrice' => $this->originalPrice,
'shippingPrice' => $this->shippingPrice,
'shippingWeightLbs' => $this->shippingWeightLbs,
'shippingWeightOz' => $this->shippingWeightOz,
'shippingMaxDays' => $this->shipping_max_days,
'shippingMinDays' => $this->shipping_min_days,
'personalized' => (bool) $this->personalized,
'personalizedOptions' => $personalizedOptions,
// 'deals' => $this->deals ?? null,
'options' => ProductOptionResource::collection($this->productOptions),
'images' => ImageResource::collection($this->images->whereNull('meta')),
'preview' => new ImageResource($this->images->where('meta', '=', 'preview')->first()),
];
}
}
}
The reason why it may be giving the null result because of the condition check. it is returning an array you need to update it to this.
if(count($this->deals))
this will check if the deal array contains an element in the array. if not it will return products.

Magento 2 Plugins / Interceptors accessing and modifying $this object

I have a plugin that i want to modify functionality of a method within specific class in Magento 2 however am not quite sure on how to access the original object and return the modified data.
Original Method
protected function _initTotals()
{
$source = $this->getSource();
$this->_totals = [];
$this->_totals['subtotal'] = new \Magento\Framework\DataObject(
['code' => 'subtotal', 'value' => $source->getSubtotal(), 'label' => __('Subtotal')]
);
/**
* Add shipping
*/
if (!$source->getIsVirtual() && ((double)$source->getShippingAmount() || $source->getShippingDescription())) {
$this->_totals['shipping'] = new \Magento\Framework\DataObject(
[
'code' => 'shipping',
'field' => 'shipping_amount',
'value' => $this->getSource()->getShippingAmount(),
'label' => __('Shipping & Handling'),
]
);
}
/**
* Add discount
*/
if ((double)$this->getSource()->getDiscountAmount()) {
if ($this->getSource()->getDiscountDescription()) {
$discountLabel = __('Discount (%1)', $source->getDiscountDescription());
} else {
$discountLabel = __('Discount');
}
$this->_totals['discount'] = new \Magento\Framework\DataObject(
[
'code' => 'discount',
'field' => 'discount_amount',
'value' => $source->getDiscountAmount(),
'label' => $discountLabel,
]
);
}
$this->_totals['grand_total'] = new \Magento\Framework\DataObject(
[
'code' => 'grand_total',
'field' => 'grand_total',
'strong' => true,
'value' => $source->getGrandTotal(),
'label' => __('Grand Total'),
]
);
/**
* Base grandtotal
*/
if ($this->getOrder()->isCurrencyDifferent()) {
$this->_totals['base_grandtotal'] = new \Magento\Framework\DataObject(
[
'code' => 'base_grandtotal',
'value' => $this->getOrder()->formatBasePrice($source->getBaseGrandTotal()),
'label' => __('Grand Total to be Charged'),
'is_formated' => true,
]
);
}
return $this;
}
This i have set to have a plugin to modify functionality of method above with di.xml:
<type name="Magento\Sales\Block\Order\Totals">
<plugin disabled="false" name="Harrigo_EverDiscountLabel_Plugin_Magento_Sales_Block_Order_Totals" sortOrder="10" type="Harrigo\EverDiscountLabel\Plugin\Magento\Sales\Block\Order\Totals"/>
</type>
Plugin
class Totals
{
public function after_initTotals(
\Magento\Sales\Block\Order\Totals $subject,
$result
) {
if ((double)$subject->getSource()->getDiscountAmount() != 0 OR $subject->getSource()->getDiscountDescription() != null) {
if ($subject->getSource()->getDiscountDescription()) {
$discountLabel = __('Offer (%1)', $source->getDiscountDescription());
} else {
$discountLabel = __('Offer');
}
$subject->_totals['discount'] = new \Magento\Framework\DataObject(
[
'code' => 'discount',
'field' => 'discount_amount',
'value' => $source->getDiscountAmount(),
'label' => $discountLabel,
]
);
}
return $subject;
}
}
Have used $subject instead of $this within the plugin, this does not work for me however. How do I access the $this object within the plugin to add / overwrite $this->_totals['discount'] and return the updated $this object from within the plugin. I have it working fine with a standard preference but would rather use a plugin if possible.
I think you should check this before implementing above code.
http://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html
As per devdocs for Magento2 protected functions can not be intercepted so We can not use plugins for that.
May be that is causing issue in your case.
Hope this helps!

Insert array into postgresql error

I using Phalcon Framework and PostgreSQL
I try to insert an array to database column type: varchar[]:
array(4) { [0]=> string(1) "1" [1]=> string(1) "6" [2]=> string(1) "9" [3]=> string(2) "12" }
But getting following error :
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
Please help me to fix this please
Here is my Model:
<?php
namespace App\Models;
use Phalcon\Mvc\Model;
use Phalcon\Validation;
use Phalcon\Validation\Validator\Uniqueness;
class Document extends Model
{
public $id;
public $relatedocument;
public function getSource()
{
return "document";
}
=====Form======
<?php
namespace App\Modules\Backend\Forms;
use Idoc\Models\Document;
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Select;
class DocumentForm extends Form
{
public function initialize($entity = null, $options = null)
{
$data = Document::find();
$this->add(new Select('relatedocument[]', $data, [
'using' => [
'id',
'name'
],
'useEmpty' => true,
'emptyText' => '....',
'multiple' => 'multiple',
'class' => 'form-control search-select'
]));
}
=====addAction======
public function addAction()
{
if ($this->request->isPost()) {
$doc = new Document();
$doc->relatedocument = $this->request->getPost('relatedocument');
if (!$doc->save()) {
$this->flash->error($doc->getMessages());
} else {
$this->flash->success("Văn bản đã được tạo");
Tag::resetInput();
}
}
$this->view->form = new DocumentForm(null);
}

ZF2 forward plugin dispatches wrong View

I have a weird problem. I am trying to widgetize my website by creating a ViewHelper which contains and this piece of code but for some reason it doesn't work as expected:
//....
$forward = $serviceManager->get('ControllerPluginManager')->get('Forward');
$view = $forward->dispatch('Application\Controller\Widgets', array('action' => 'notexistingaction'));
$view1 = $forward->dispatch('Application\Controller\Widgets', array('action' => 'existingaction'));
\Zend\Debug\Debug::dump($view);
\Zend\Debug\Debug::dump($view1);
//....
The result is
object(Zend\View\Model\ViewModel)#713 (7) {
["captureTo":protected] => string(7) "content"
["children":protected] => array(0) {
}
["options":protected] => array(0) {
}
["template":protected] => string(9) "error/404"
["terminate":protected] => bool(false)
["variables":protected] => array(4) {
["content"] => string(14) "Page not found"
["message"] => string(15) "Page not found."
["reason"] => string(32) "error-controller-cannot-dispatch"
["display_exceptions"] => bool(true)
}
["append":protected] => bool(false)
}
object(Zend\View\Model\ViewModel)#716 (7) {
["captureTo":protected] => string(7) "content"
["children":protected] => array(0) {
}
["options":protected] => array(0) {
}
["template":protected] => string(9) "error/404"
["terminate":protected] => bool(false)
["variables":protected] => object(Zend\View\Variables)#717 (2) {
["strictVars":protected] => bool(false)
["storage":"ArrayObject":private] => array(3) {
["message"] => string(15) "Page not found."
["reason"] => string(32) "error-controller-cannot-dispatch"
["display_exceptions"] => bool(true)
}
}
["append":protected] => bool(false)
}
Question WHY ??
Technically there should be one with error and other one to be displayed its content .. but for some reason both appears as 404
Any help please?
Thanks

InputFilter "setRequired" not working for html5 multiple

I'm having hard time with a weird behaviour of fileinput.
This is my form:
namespace Frontend\Form;
use NW\Form\Form;
use Zend\InputFilter;
use Zend\Form\Element;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
class EnrollStructure extends Form implements ServiceManagerAwareInterface
{
protected $sm;
public function __construct($name=null) {
parent::__construct("frmEnrollStructure");
$this->setAttribute("action", "/registrazione_struttura/submit")
->setAttribute('method', 'post')
->setAttribute("id", "iscrizione_struttura")
->setAttribute("class", "form fullpage");
$this->addInputFilter();
}
public function init()
{
$structureFs = $this->sm->get('Structure\Form\Fieldsets\Structure');
$structureFs->setUseAsBaseFieldset(true);
$structureFs->remove("id")
->remove("creationTime")
->remove("latLon");
$file = new Element\File("images");
$file->setAttribute('multiple', true);
$this->add($structureFs)->add($file);
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Iscriviti',
'id' => 'sbmtEnrollStructure',
'class' => 'submit_btn'
),
));
$this->setValidationGroup(
array(
'structure' =>
array(
'companyname',
'vatNumber',
'addressStreet',
'addressZip',
'addressCity',
'addressRegion',
'fax',
'publicPhone',
'publicEmail',
'website',
'status',
'ownerNotes',
'category',
'subcategory',
"facilities",
"agreeOnPolicy",
"agreeOnPrivacy",
"subscribeNewsletter",
"contact" => array("name", "surname", "email", "role", "phone"),
),
"images"
));
}
/**
* Set service manager
*
* #param ServiceManager $serviceManager
*/
public function setServiceManager(ServiceManager $serviceManager)
{
$this->sm = $serviceManager;
}
public function addInputFilter()
{
$inputFilter = new InputFilter\InputFilter();
// File Input
$fileInput = new InputFilter\FileInput('images');
$fileInput->setRequired(true);
$fileInput->getValidatorChain()
->attachByName('filesize', array('max' => "2MB"))
->attachByName('filemimetype', array('mimeType' => 'image/png,image/x-png,image/jpg,image/jpeg'))
->attachByName('fileimagesize', array('maxWidth' => 2048, 'maxHeight' => 2048));
$inputFilter->add($fileInput);
$this->setInputFilter($inputFilter);
}
}
Basically, I mainly use a fieldset which contains most of the data I request to the user, plus a File input field.
This is the Fieldset Structure: (most important parts..)
use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Validator\Identical;
use Zend\Validator\NotEmpty;
use Zend\Validator\Regex;
use Zend\Validator\StringLength;
class Structure extends Fieldset implements InputFilterProviderInterface, ServiceManagerAwareInterface
{
protected $sm;
public function __construct()
{
parent::__construct('structure');
}
public function init()
{
$this->setHydrator(new DoctrineHydrator($this->_entityManager(),'Structure\Entity\Structure'));
$this->setObject($this->sm->getServiceLocator()->get("Structure_Structure"));
$id = new Element\Hidden("id");
$name = new Element\Text("companyname");
$name->setLabel("Ragione Sociale");
...........
}
public function getInputFilterSpecification()
{
return array
(
"id" => array(
"required" => false,
),
"companyname" => array(
"required" => true,
"validators" => array(
array('name' => "NotEmpty", 'options' => array("messages" => array( NotEmpty::IS_EMPTY => "Inserire la ragione sociale")))
),
),
.....
}
}
This is my controller:
public function submitAction()
{
try {
$this->layout("layout/json");
$form = $this->getForm('Frontend\Form\EnrollStructure');
//$form->addInputFilter();
$structure = $this->getServiceLocator()->get("Structure_Structure");
$viewModel = new ViewModel();
$request = $this->getRequest();
if ($request->isPost())
{
$post = array_merge_recursive
(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($post);
if ($form->isValid())
{
$structure = $form->getObject();
$contact = $structure->getContact();
$this->getServiceLocator()->get('Structure_ContactService')->save($contact);
$files = $request->getFiles()->toArray();
if(isset($files['images']))
{
$count = 3;
foreach($files['images'] as $pos => $file)
{
$fpath = $this->getServiceLocator()->get('RdnUpload\Container')->upload($file);
if(!empty($fpath))
{
if(--$count ==0) break;
$asset = $this->getServiceLocator()->get("Application_AssetService")->fromDisk($fpath, $file['name']);
$this->getServiceLocator()->get("Application_AssetService")->save($asset);
$structure->addImage($asset);
}
}
}
$this->getServiceLocator()->get('Structure_StructureService')->save($structure);
$retCode = RetCode::success(array("iscrizione_struttura!" => array("form_submit_successfull")), true);
}
else
{
$messages = $form->getMessages();
if(empty($messages))
$retCode = RetCode::error(array("iscrizione_struttura" => array("need_at_least_one_file" => "missing file")), true);
else
$retCode = RetCode::error(array("iscrizione_struttura" => $messages), true);
}
$viewModel->setVariable("retcode", $retCode);
return $viewModel;
}
} catch(Exception $e)
{
throw $e;
}
}
The strange thing is that if i remove from the field "images" the "multiple" attribute everything works fine, causing the form not to validate and i get this message:
[images] => Array
(
[fileUploadFileErrorFileNotFound] => File was not found
)
While, if i set the attribute multiple, and the user does not upload a file i get no error, but the form gets invalidated (this is the reason for this "bad" code in my controller:)
$messages = $form->getMessages();
if(empty($messages))
$retCode = RetCode::error(array("iscrizione_struttura" => array("need_at_least_one_file" => "missing file")), true);
else
$retCode = RetCode::error(array("iscrizione_struttura" => $messages), true);
I found the problem was caused by the Jquery form plugin, without it it works fine. :( In case somebody needs, I think the correct action code can be found here (I haven't tryied it anyway)
https://github.com/cgmartin/ZF2FileUploadExamples/blob/master/src/ZF2FileUploadExamples/Controller/ProgressExamples.php