`BulkWrite error :: norepl` mongodb php BulkWrite - php

I getting this is exception in my application, and don't understand why. This exception throw in for one collection, over collection not throw this exception, with processed insert(),update(), or delete()
/**
* insert to mongo db method
* #param $dataArray
* #param $collection
*/
static function insert($dataArray, $collection) {
$connect = Core_Model_Mongo::getConnect();
$write = new MongoDB\Driver\BulkWrite();
$writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY);
$write->insert($dataArray);
$connect->executeBulkWrite(
Config_Db::getConf()['mongodb']['db'].'.'.$collection,
$write,
$writeConcern
);
}
end get connect method
/**
* #return \MongoDB\Driver\Manager
*/
static function getConnect() {
if(!is_null(self::$_connect)) {
return self::$_connect;
}
self::$_connect = new \MongoDB\Driver\Manager(Config_Db::getConf()['mongodb']['connect']);
return self::$_connect;
}
data save in collection success full, and this exception not take insert(),update() and other methods. I temporary resolve this question by try catch block
try {
// my code
} catch(MongoDB\Driver\Exception\BulkWriteException $error) {
Core_App::log(var_export($error,true));
}
but this is resolve not correct because I need application without any exception,error,notice, and over log level error.

Related

How is the access_token value created in drupal/simple_oauth?

The drupal/simple_oauth module creates an oauth2_token table. This table has a column value and I've examined the source code but I cannot work out how this value is generated.
To make this a little bit more complicated, I don't have this service running locally, and I don't have access to the remote server it is running on, I only have access to the database itself.
I am creating a Python service that is using the Drupal database (because reasons). I am able to generate all the required data except this value field.
I can copy the value field from one of the existing access tokens, and use it in a new record I create via a SQL INSERT. The JWT I create from this record's value works correctly with the protected endpoint. However, if I set an arbitrary value like a UUID, the request to the protected resource fails with the following error response:
{
"error": "permission_denied",
"error_description": "The 'debug simple_oauth tokens' permission is required.",
"status_code": 403,
"detail": "permission_denied"
}
The value is used in the jti of the JWT and I can see in src/Entities/AccessTokenEntity.php that this is set to $this->getIdentifier(); (<-- comments are mine):
public function convertToJWT() {
$private_claims = [];
\Drupal::moduleHandler()
->alter('simple_oauth_private_claims', $private_claims, $this);
if (!is_array($private_claims)) {
$message = 'An implementation of hook_simple_oauth_private_claims_alter ';
$message .= 'returns an invalid $private_claims value. $private_claims ';
$message .= 'must be an array.';
throw new \InvalidArgumentException($message);
}
$id = $this->getIdentifier(); /* <-- NOTE */
$now = new \DateTimeImmutable('#' . \Drupal::time()->getCurrentTime());
$key_path = $this->privateKey->getKeyPath();
$key = InMemory::file($key_path);
$config = Configuration::forSymmetricSigner(new Sha256(), $key);
$builder = $config->builder()
->permittedFor($this->getClient()->getIdentifier())
->identifiedBy($id) /* <-- SET THE JTI */
->withHeader('jti', $id)
->issuedAt($now)
->canOnlyBeUsedAfter($now)
->expiresAt($this->getExpiryDateTime())
->relatedTo($this->getUserIdentifier())
->withClaim('scope', $this->getScopes());
And this is where my investigation has stopped, as I cannot work out where getIdentifier() is implemented.
I cross-posted this question to Drupal Answers and #apaderno noted this wasn't a Drupal specific question, which nudged me towards the source for The source for PHP OAuth 2.0 Server.
The source of the value column is the generateUniqueIdentifier function in AbstractGrant.php:
/**
* Generate a new unique identifier.
*
* #param int $length
*
* #throws OAuthServerException
*
* #return string
*/
protected function generateUniqueIdentifier($length = 40)
{
try {
return \bin2hex(\random_bytes($length));
// #codeCoverageIgnoreStart
} catch (TypeError $e) {
throw OAuthServerException::serverError('An unexpected error has occurred', $e);
} catch (Error $e) {
throw OAuthServerException::serverError('An unexpected error has occurred', $e);
} catch (Exception $e) {
// If you get this message, the CSPRNG failed hard.
throw OAuthServerException::serverError('Could not generate a random string', $e);
}
// #codeCoverageIgnoreEnd
}

How to print custom message in try catch - php laravel

I need to write to log some data when exception occurred, since it is dynamic data and I need the message I tried with simple code, just to write 'Boom' if exception occurred.
However just the automatic exception data written in logs (as before the try catch).
can someone advise how to print to log in the catch?
I just need to add additional text to the exception, just to be more specific
try {
$sheet->setCellValue($cell,$innervalue);
} catch(Exception $e) {
$message = 'Can not set value: '.$innervalue .' in cell ' .$cell .$headerArray[$headerIndex];
\Log::info('boom');
}
and in the logs nothing displayed
php artisan make:Exception SomeAweSomeException
This way you have your own controle of how the exception should look and handle. Also you can use standards wich makes you code look cleaner.
class SomeCustomException extends Exception
{
// ...
/**
* Get the exception's context information.
*
* #return array
*/
public function context()
{
return ['order_id' => $this->orderId];
}
}
use Exception;
class SetDeliverDateToFarAwayException extends Exception
{
public function __construct()
{
parent::__construct(
'Selecting more than three days into the future is not allowed'
);
}
}
and now my method wich creates the error message.
/**
* Finalizes the scheduler
*
* #return string
* #throws SetDeliverDateToFarAwayException|Throwable
*/
public function set(): string
{
$today = Carbon::now();
$deliver = new Carbon();
$deliver->year($this->year ?? $today->year);
$deliver->month($this->month ?? $today->month);
$deliver->day($this->day ?? $today->day);
$deliver->hour($this->hour ?? $today->hour);
$deliver->minute($this->minute ?? $today->minute);
#Mail gun can max schedule mail for 3 days in the future. So we throw an Exception if the date is to big.
throw_if($deliver->diffInHours($today) > 72, new SetDeliverDateToFarAwayException());
return Mail::schedule($deliver->toDateTimeString());
}
this what worked for me
try {
$sheet->setCellValueExplicit('WELL DONE');
}
catch (\Exception $e) {
$errorMsg = 'the value of:\' ' .$innervalue . '\' in cell ' . $cell . ' in header: ' . $headerArray[$headerIndex] . 'problematic' ;
\Log::error($errorMsg);
\Log::error($e->getMessage());
\Log::error($e->getTraceAsString());
throw new Exception($e->getMessage());
}
To get the exception log message use it like this -
try {
} catch(Exception $e) {
Log::info(json_encode($e->getMessage()));
}

How to unit test this try catch

I'm trying to 100% code coverage my service. Here is a method:
<?php
* Search to public accounts.
*
* #param string $query
*
* #return TwitterResponse
*/
public function search(string $query): TwitterResponse
{
try {
$response = $this->client->getClient()->get(UserEnum::URI_SEARCH, [
'query' => ['q' => $query,]
]);
} catch (ClientException $e) {
$response = $e->getResponse();
}
return new TwitterResponse($response);
}
It simply GET a user with Twitter API.
In my opinion, I should develop two tests : one for the try and one for the catch. Bellow is my test for the try.
<?php
/**
* #return void
*/
public function setUp(): void
{
$this->prophet = new Prophet();
$this->client = $this->prophet->prophesize(Client::class);
$this->client->get(Argument::any(), Argument::any())->willReturn(new TwitterResponse(new Response()));
$this->client->post(Argument::any(), Argument::any())->willReturn(new TwitterResponse(new Response()));
$this->twitterClient = $this->prophet->prophesize(TwitterClient::class);
$this->twitterClient->getClient()->willReturn($this->client);
$this->userService = new UserService($this->twitterClient->reveal());
}
/**
* Tests if a TwitterResponse is returned with status HTTP_OK.
*
* #return void
*/
public function testGetOk(): void
{
$actual = $this->userService->get('');
$this->assertEquals(get_class($actual), TwitterResponse::class);
$this->assertEquals(HttpResponse::HTTP_OK, $actual->getStatusCode());
}
Bellow the code coverage of get().
As you can see, I don't test the catch case. How can I do it ? I already tried to mock a 404 HTTP response catch something but it did not work. Do you have an idea of how I can do it ?
Thanks.
EDIT : I tried this for the catch case ->
public function testGetKo(): void
{
$response = new TwitterResponse(new Response(HttpResponse::HTTP_NOT_FOUND));
$response->setStatusCode(HttpResponse::HTTP_NOT_FOUND);
$this->client = $this->prophet->prophesize(Client::class);
$this->client->get(Argument::any(), Argument::any())->willReturn($response);
$this->twitterClient = $this->prophet->prophesize(TwitterClient::class);
$actual = $this->userService->get('');
$this->assertEquals(get_class($actual), TwitterResponse::class);
$this->assertEquals(HttpResponse::HTTP_NOT_FOUND, $actual->getStatusCode());
}
Phpunit returns : Failed asserting that 200 matches expected 404. It seems that my mock client doesn't work well.
I know, it's an old post, but..
Maybe try to mock client, and when it's triggered throw exception?
So when you throw ClientException, you should check for TwitterResponse result. And when you throw DummyException, you should expect DummyException.
This is untested, as I don't usually use prophecy, but I do simialry with other mocking frameworks:
public function testGetKo(): void
{
// ... other setup
$exception = new ClientException();
$this->client = $this->prophet->prophesize(Client::class);
$this->client->get(Argument::any(), Argument::any())->willThrow($exception);
And you will likely add $this->expectException(ClientException::class); before you run the function being tested.

How to get parse errors with DOMDocument::loadXML()

I am trying to load xml which has mismatched tags and I expected something like this to work but without luck.
try{
$xml=new \DOMDocument('1.0','utf-8');
$xml->loadXML(file_get_contents($file),
}catch (\Exception $e){
echo $e->getMessage());
}
Now I really need to throw an exception for parse errors. I tried to pass options to loadXML
LIBXML_ERR_ERROR|LIBXML_ERR_FATAL|LIBXML_ERR_WARNING
again no luck. Please guide me how to catch all these parse errors.
Edit
As suggested by #Ghost in comments, I came around this solution
abstract class XmlReadStrategy extends AbstractReadStrategy
{
/** #var array */
protected $importAttributes;
/**
* #param $fileFullPath
* #param $fileName
*/
public function __construct($fileFullPath,$fileName)
{
parent::__construct($fileFullPath,$fileName);
libxml_use_internal_errors(true);
}
/**
*
*/
protected function handleXmlException(){
$this->dataSrc=array();
foreach(libxml_get_errors() as $e){
$this->logger->append(Logger::ERROR,'[Error] '.$e->message);
}
}
/**
* Import xml file
* #param string $file
* #throws \Exception
*/
protected function loadImportFileData($file)
{
try{
$xml=new \DOMDocument('1.0','utf-8');
if(!$xml->loadXML(file_get_contents($file))){
$this->handleXmlException();
}
$this->dataSrc=$this->nodeFilter($xml);
}catch (\Exception $e){
$this->logger->append(Logger::ERROR,$e->getMessage());
$this->dataSrc=array();
}
}
....
}
So the trick is to call libxml_use_internal_errors(true); and then check loadXML() status e.g
if(!$xml->loadXML(file_get_contents($file))){
$this->handleXmlException();
}
I don't know if this libxml_use_internal_errors(true); has any side-effect so far
You can enable libxml_use_internal_errors and get errors with libxml_get_errors()
libxml_use_internal_errors(true);
$xml = new DOMDocument('1.0','utf-8');
if ( !$xml->loadxml(file_get_contents($file)) ) {
$errors = libxml_get_errors();
var_dump($errors);
}

Should I check if array/collection value exists before trying to get it?

Should I check if a key exists and then get it or just get it (when I need to get it, not check if its set)?
What is more reliable? safer? faster?
Examples:
1) PHP redis (https://github.com/nicolasff/phpredis)
if ($redis->exists('key'))
echo $redis->get('key');
// VS
if ($value = $redis->get('key'))
echo $value;
2) PHP phalcon cookies(http://docs.phalconphp.com/pt/latest/reference/cookies.html)
if ($this->cookies->has('remember-me'))
echo $this->cookies->get('remember-me')->getValue()
// VS
if ($value = $this->cookies->get('remember-me')->getValue())
echo $value;
Thank you!
My interpretation of this problem is:
I don't like writing things like
if ($value = $redis->get('key'))
echo $value;
it makes code unclear.
Also, why is checking if variable exists so important? Because it simplifies control flow.
Let's consider that you're grabbing some data from service to render it on page. You can write low quality code with multiple ifs, but you can also try something like this:
offerServiceImpl.php
class offerServiceImpl implements offerService {
//... (some methods)
/**
* #param int $offerId
* #return Offer
* #throws InvalidArgumentException
* #throws RuntimeException
*/
public function getOffer($offerId)
{
if (!$offerId || !is_numeric($offerId)) {
throw new InvalidArgumentException("Invalid offer id: " . $offerId);
}
$offer = $this->offerDao->get($offerId);
if (!$offer) {
//could be your own exception class
throw new RuntimeException("Could not found offer " . $offerId);
} else {
return $offer;
}
}
}
offersControler.php
class offersController extends AbstractController{
public function index($id){
//... some code
try{
$offer = $this->offerService->getOffer($id);
} catch (InvalidArgumentException $ex) {
//log error, perform redirect to error 500
} catch (RuntimeException $ex){
//log another error, perform redirect to error 404
} catch (Exception $ex){
//log error, perform redirect to error 500
}
}
}

Categories