Laravel ErrorException Undefined offset: 0 - runtime-error

I am facing this error in laravel 5.
Here is the controller function in which I am facing the error (in the line where I do ($vendor->client[0]->id) :
public function show($username) {
Log::info('Vendors Controller : show function with '.$username);
$vendor = VendorProfile::where('username', $username)->first();
$output = print_r($vendor,1);
Log::info($output);
if($vendor) {
Log::info('client '. $vendor->client);
$client = Client::find($vendor->client[0]->id);
$title = $client->profile->company_name;
$output is printed as:
[2015-06-15 21:34:43] local.INFO: App\models\VendorProfile Object
(
[table:protected] => vendor_profile
[guarded:protected] => Array
(
[0] => id
)
[morphClass:protected] => MorphVendorProfile
[connection:protected] =>
[primaryKey:protected] => id
[perPage:protected] => 15
[incrementing] => 1
[timestamps] => 1
[attributes:protected] => Array
(
[id] => 16
[first_name] => some name
[last_name] =>
[company_name] => some name
[contact_number] => 1234567890
[username] => username
[profile_photo] =>
[photo_mime_type] =>
[cover_photo] =>
[cover_photo_mime_type] =>
[address] =>
[city_id] => 1
[zip_code] =>
[story] =>
[establishment_date] =>
[pricing] =>
[education] =>
[services_offered] =>
[assignments_undertook] =>
[advanced_fees] =>
[equipments] =>
[about_service] =>
[coins] => 500
[created_at] => 2015-06-15 20:21:45
[updated_at] => 2015-06-15 20:21:45
)
[original:protected] => Array
(
[id] => 16
[first_name] => some name
[last_name] =>
[company_name] => some name
[contact_number] => 1234567890
[username] => username
[profile_photo] =>
[photo_mime_type] =>
[cover_photo] =>
[cover_photo_mime_type] =>
[address] =>
[city_id] => 1
[zip_code] =>
[story] =>
[establishment_date] =>
[pricing] =>
[education] =>
[services_offered] =>
[assignments_undertook] =>
[advanced_fees] =>
[equipments] =>
[about_service] =>
[coins] => 500
[created_at] => 2015-06-15 20:21:45
[updated_at] => 2015-06-15 20:21:45
)
[relations:protected] => Array
(
)
[hidden:protected] => Array
(
)
[visible:protected] => Array
(
)
[appends:protected] => Array
(
)
[fillable:protected] => Array
(
)
[dates:protected] => Array
(
)
[casts:protected] => Array
(
)
[touches:protected] => Array
(
)
[observables:protected] => Array
(
)
[with:protected] => Array
(
)
[exists] => 1
)
The models VendorProfile and Client are connected as:
in VendorProfile model:
protected $morphClass = 'MorphVendorProfile';
// Defining 'Polymorphic' Relationship with Client Model
public function client() {
return $this->morphMany('App\models\Client', 'profile');
}
and I have an alias in my config/app.php:
'MorphVendorProfile'=> 'App\models\VendorProfile'
in Client model :
public function profile() {
return $this->morphTo();
}
Update:
This error has occurred while migrating the code from laravel 4.2 to laravel 5. So right now, when I run the previous code that was based on 4.2 version with the SAME database, and it didn't throw me any error, so I think problem is with the code, not database. I am certain that there is a problem with 'morph' relationships, I had to modify a bit in the process of migrating to make it work on other pages.
here is the morphTo function in my Eloquent/Model.php:
/**
* Define a polymorphic, inverse one-to-one or many relationship.
*
* #param string $name
* #param string $type
* #param string $id
* #return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function morphTo($name = null, $type = null, $id = null)
{
// If no name is provided, we will use the backtrace to get the function name
// since that is most likely the name of the polymorphic interface. We can
// use that to get both the class and foreign key that will be utilized.
if (is_null($name))
{
list(, $caller) = debug_backtrace(false, 2);
$name = snake_case($caller['function']);
}
list($type, $id) = $this->getMorphs($name, $type, $id);
// If the type value is null it is probably safe to assume we're eager loading
// the relationship. When that is the case we will pass in a dummy query as
// there are multiple types in the morph and we can't use single queries.
if (is_null($class = $this->$type))
{
Log::info('eagerly loading');
return new MorphTo(
$this->newQuery(), $this, $id, null, $type, $name
);
}
// If we are not eager loading the relationship we will essentially treat this
// as a belongs-to style relationship since morph-to extends that class and
// we will pass in the appropriate values so that it behaves as expected.
else
{
Log::info('not eagerly loading');
Log::info($class);
$instance = \App::make('\App\models\\'.$class);
$output = print_r($instance,1);
Log::info('*'.$output.'*');
return new MorphTo(
$instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name
);
}
}

Check your namespaces. Make sure that the polymorphic relationship that you have setup references the full namespace in both the Vendor and Client models

Related

What data is POSTed to a shippo webhook?

I would like to implement a shippo webhook in order to know the delivery status of my shipments, their documentation is a little unclear... I don't know what information will be passed to my script
I have setup a test URL and a live one and have added those to my account, in API -> Webhooks.
Whenever my script is requested either via the live or test URLs I get empty arrays, no data. Please help me figure this out. Anyone from Shippo??
Here is what I have so far:
<?php
namespace MW\PublicBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ShippoController extends Controller
{
/**
* #Route("/shippo/", name="shippo_web_hook")
* #Method("GET|POST")
*/
public function webHookAction(Request $request)
{
if ($request->getMethod() == 'POST'){
$post = $request->request->all();
} elseif ($request->getMethod() == 'GET'){
$post = $request->query->all();
}
file_put_contents(__DIR__ . '/shippo.txt', print_r($post,true));
$mailer = $this->get('swiftmailer.mailer.transactional');
$messageObject = \Swift_Message::newInstance()
->setSubject('Shippo Webhook Posted DATA')
->setFrom('emai#example.com')
->setTo('email#example.com')
->setBody(print_r($post,true) . "\n" . print_r($_REQUEST,true) . "\n" . print_r($_POST,true));
try {
$mailer->send($messageObject);
} catch (\Exception $e){
}
return new Response('OK');
}
}
As you can see I should be able to catch some incoming data but I get nothing but empty arrays..
Indeed my script is receiving straight up JSON, thank you to mootrichard for sharing the requestb.in tool, with it I was able to see all the headers and data sent, just for future reference this is what I got.
namespace MW\PublicBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ShippoController extends Controller
{
/**
* #Route("/shippo/", name="shippo_web_hook")
* #Method("GET|POST")
*/
public function webHookAction(Request $request)
{
$headers = $request->headers->all();
$content = $request->getContent();
if (!empty($content))
{
$post = json_decode($content, true);
}
if (isset($headers['x-shippo-event'][0]) && $headers['x-shippo-event'][0] == 'track_updated' &&
(isset($headers['content-type'][0]) && $headers['content-type'][0] == 'application/json')){
if (count($post) > 0) {
file_put_contents(__DIR__ . '/shippo.txt', print_r($headers, true) . "\n\n\n" . print_r($post, true));
}
}
return new Response('OK');
}
}
And the contents of shippo.txt is:
Array
(
[host] => Array
(
[0] => ******
)
[user-agent] => Array
(
[0] => python-requests/2.9.1
)
[content-length] => Array
(
[0] => 1021
)
[accept] => Array
(
[0] => */*
)
[accept-encoding] => Array
(
[0] => gzip, deflate
)
[content-type] => Array
(
[0] => application/json
)
[shippo-api-version] => Array
(
[0] => 2014-02-11
)
[x-forwarded-for] => Array
(
[0] => **.**.***.**
)
[x-original-host] => Array
(
[0] => *****
)
[x-shippo-event] => Array
(
[0] => track_updated
)
[x-php-ob-level] => Array
(
[0] => 0
)
)
Array
(
[messages] => Array
(
)
[carrier] => usps
[tracking_number] => 123
[address_from] => Array
(
[city] => Las Vegas
[state] => NV
[zip] => 89101
[country] => US
)
[address_to] => Array
(
[city] => Spotsylvania
[state] => VA
[zip] => 22551
[country] => US
)
[eta] => 2017-09-05T01:35:10.231
[original_eta] => 2017-09-05T01:35:10.231
[servicelevel] => Array
(
[token] => usps_priority
[name] => Priority Mail
)
[metadata] => Shippo test webhook
[tracking_status] => Array
(
[status] => UNKNOWN
[object_created] => 2017-08-31T01:35:10.240
[status_date] => 2017-08-31T01:35:10.240
[object_id] => ac0e0c060d6e43b295c460414ebc831f
[location] => Array
(
[city] => Las Vegas
[state] => NV
[zip] => 89101
[country] => US
)
[status_details] => testing
)
[tracking_history] => Array
(
[0] => Array
(
[status] => UNKNOWN
[object_created] => 2017-08-31T01:35:10.240
[status_date] => 2017-08-31T01:35:10.240
[object_id] => ac0e0c060d6e43b295c460414ebc831f
[location] => Array
(
[city] => Las Vegas
[state] => NV
[zip] => 89101
[country] => US
)
[status_details] => testing
)
)
[transaction] =>
)
According to their documentation they're just sending you a straight JSON response, not a key/value pair of data that you can get from the request parameters. You would want to do something like this instead:
$data = json_decode($request->getContent(), true);
This documentation is from Silex but it's using the same components as Symfony to receive a accept a JSON request body.

MoneyField isChanged always returning true

I have a DataObject Confirmation that looks like this:
<?php
class Confirmation extends DataObject
{
private static $db = array(
'Reimbursement' => 'Money',
'SomeText' => 'Varchar(255)'
);
private static $has_one = array(
'Page' => 'Page'
);
public function getCMSFields()
{
$fields = parent::getCMSFields();
$reimbursementField = MoneyField::create('Reimbursement');
$someTextField = TextField::create('SomeText');
$reimbursementField->setAllowedCurrencies(array('SEK'));
$fields->addFieldsToTab(
'Root.Main',
array(
$reimbursementField,
$someTextField
)
);
return $fields;
}
public function onBeforeWrite()
{
parent::onBeforeWrite();
if($this->isChanged('Reimbursement')) SS_Log::log( print_r ( 'changed', true ), SS_Log::WARN );
}
}
if($this->isChanged('Reimbursement')) in the onBeforeWrite() function will always evaluate to true. Regardless of what is being changed. Even when saving without making any changes - it will fire the log function.
Edit: Checking the stacktrace with SS_Backtrace::backtrace() in Money.php's setValue() function I find that every time I save the Confirmation DataObject, setValue() is called without passing the $markChanged parameter set to false, from DataObject.php line 1281, resulting in the $isChanged flag being set to true, and the field always behaving as if it has changed.
When logging DataObject's getChangedFields() function I get the output below (when saving without making any changes). Notice the Reimbursement field being present, and before being empty. What am I missing here?
[22-Mar-2016 16:28:07] Warning at framework/model/DataObject.php line 2597: Array
(
[Reimbursement] => Array
(
[before] =>
[after] => Money Object
(
[currency:protected] => SEK
[amount:protected] => 25000
[isChanged:protected] => 1
[locale:protected] =>
[currencyLib:protected] => Zend_Currency Object
(
[_options:protected] => Array
(
[position] => 8
[script] =>
[format] =>
[display] => 2
[precision] => 2
[name] => svensk krona
[currency] => SEK
[symbol] => kr
[locale] => sv_SE
[value] => 0
[service] =>
[tag] => Zend_Locale
)
)
[allowedCurrencies:protected] =>
[value:protected] =>
[tableName:protected] =>
[name:protected] => Reimbursement
[arrayValue:protected] =>
[defaultVal:protected] =>
[failover:protected] =>
[customisedObject:protected] =>
[objCache:ViewableData:private] => Array
(
)
[class] => Money
[extension_instances:protected] => Array
(
)
[beforeExtendCallbacks:protected] => Array
(
)
[afterExtendCallbacks:protected] => Array
(
)
)
[level] => 2
)
)

multiple choice dropdown with option groups using symfony “entity”?

I have the entity Property with manyToMany to Feature that is oneToMany of FeatureType. The multi-choice drop-down is being implemented in the Property create form.
PropertyRoomAdmin.php
protected function configureFormFields(FormMapper $formMapper)
{
$property = $this->getProperty();
$featuresChoices = $this->getRepository('TestBundle:Feature')->getChoicesWithCategoryGroup();
$formMapper
->add('features', 'entity', array(
'label' => '設備(こだわり条件?)',
'class' => 'TestBundle:Feature',
'choices' => $featuresChoices,
'property' => 'name'
))
;
}
FeatureRepository.php
public function getChoicesWithCategoryGroup()
{
$choices = array();
$qb = $this->createQueryBuilder('p');
$qb->select('p, c');
$qb->LeftJoin('p.featureCategory', 'c');
$qb->orderBy('c.name', 'DESC')->addOrderBy('p.name', 'DESC');
$products = $qb->getQuery()->execute();
$choices = [];
foreach ($products as $product) {
$choices[$product->getFeatureCategory()->getName()][] = $product;
}
return $choices;
}
Neither the property "features" nor one of the methods "addFeatur()"/"removeFeatur()", "addFeature()"/"removeFeature()",
"setFeatures()", "features()", "__set()" or "__call()" exist and have
public access in class "TestBundle\Entity\PropertyRoom".
I tried 'multiple' => true code got error
->add('features', 'entity', array(
'label' => '設備(こだわり条件?)',
'class' => 'EstateBundle:Feature',
'choices' => $featuresChoices,
'property' => 'name',
'multiple'=> true,
'required' => false
))
ERROR - Failed to create object: EstateBundle\Entity\PropertyRoom
Context: {"exception":"Object(Sonata\AdminBundle\Exception\ModelManagerException)","previous_exception_message":"An exception occurred while executing 'INSERT INTO property_room_features (property_room_id, feature_id) VALUES (?, ?)' with params [168, 50]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '168-50' for key 'PRIMARY'"}
Where you setup your options array:
foreach ($products as $product) {
$choices[$product->getFeatureCategory()->getName()][] = $product;
}
Change it to something like this:
foreach ($products as $product) {
$choices[$product->getFeatureCategory()->getName()][$product->getName()] = $product->getId();
}

Symfony2 predefined parameters

I find some predefined parameters in Symfony2 configuration files, ie. %kernel.root_dir%, %kernel.debug%.
Is there a comprehensive list of these somewhere?
They're under Symfony\Component\HttpKernel\Kernel.php;
/**
* Returns the kernel parameters.
*
* #return array An array of kernel parameters
*/
protected function getKernelParameters()
{
$bundles = array();
foreach ($this->bundles as $name => $bundle) {
$bundles[$name] = get_class($bundle);
}
return array_merge(
array(
'kernel.root_dir' => $this->rootDir,
'kernel.environment' => $this->environment,
'kernel.debug' => $this->debug,
'kernel.name' => $this->name,
'kernel.cache_dir' => $this->getCacheDir(),
'kernel.logs_dir' => $this->getLogDir(),
'kernel.bundles' => $bundles,
'kernel.charset' => $this->getCharset(),
'kernel.container_class' => $this->getContainerClass(),
),
$this->getEnvParameters()
);
}
You can also see them in app/cache/dev/appDevDebugProjectContainer.php:getDefaultParameters() (it's at the end of the file), along with all the other parameters available to your application.
/**
* Gets the default parameters.
*
* #return array An array of the default parameters
*/
protected function getDefaultParameters()
{
return array(
'kernel.root_dir' => $this->targetDirs[2],
'kernel.environment' => 'dev',
'kernel.debug' => true,
'kernel.name' => 'app',
'kernel.cache_dir' => __DIR__,
'kernel.logs_dir' => ($this->targetDirs[2].'/logs'),
...
);
}

How to test inner arrays with phpunit

I have to test an array with inner arrays.
my array looks like the following.
$testdata=Array
(
[0] => Array
(
[label] => 'Ammy'
[idr] => 'user7'
[rel] => 7
)
[1] => Array
(
[label] => 'sidh'
[idr] => user8
[rel] => 8
)
[2] => Array
(
[label] => 'Alan'
[idr] => 'user9'
[rel] => 9
)
)
in this case my requirement is to assert whether the keys for inner array present using assertArrayHasKey() assertion of phpunit. I tried to do it like this
foreach ($testdata as $values) {
//print_r($values);
$this->assertArrayHasKey('idr', $values);
$this->assertArrayHasKey('rel', $values);
}
but this is not working for me. even the control does not go inside the foreach() loop.
please suggest me some solution for this.
foreach ($testdata as $values) {
//print_r($values);
$this->assertArrayHasKey('idr', $values);
$this->assertArrayHasKey('rel', $values);
}
this part in my question works fine. actually i was not getting the array itself in the test scenario. so it was not going inside the foreach(). now it is solved. i had a mistake in passing args to the function.
This is the example usage
/** Example One */
$testData = [
[
'label' => '',
'idr' => ''
], [
'label' => '',
'idr' => ''
], [
'label' => '',
'idr' => ''
]
];
$this->assertArrayStructure([
['label','idr']
], $testData);
/** Example Two */
$testData = [
'result' => true,
'data' => [
'col_1' => '',
'col_2' => ''
],
];
$this->assertArrayStructure([
'result', 'data' => ['col_1', 'col_2']
], $testData);
/** Example Three */
$testData = [
'result' => true,
'data' => [
[
'col_1' => '',
'col_2' => ''
],
[
'col_1' => '',
'col_2' => ''
]
],
];
$this->assertArrayStructure([
'result', 'data' => ['col_1', 'col_2']
], $testData, true);
Here is function
/**
* Like as assertJsonStructure
*
* #param array $data
* #param array $structures #e.g., [ key_1, key_2 => [child_key]]
* #param bool $dataHasMultiArray #e.g., $data[0][key]
*/
protected function assertArrayStructure(array $structures, array $data, bool $dataHasMultiArray = false)
{
$i = 0;
foreach ($structures as $index => $key) {
if (!is_numeric($index)) {
$this->assertArrayHasKey($index, $data);
}
if (is_string($key)) {
$this->assertArrayHasKey($key, $data);
}
if (is_array($key)) {
$this->assertArrayHasKeys($key, $dataHasMultiArray ? $data[$index][$i] : $data[$index]);
$i++;
}
}
}
/**
* #param $structures
* #param array $data
*/
protected function assertArrayHasKeys($structures, array $data)
{
foreach ($structures as $key) {
$this->assertArrayHasKey($key, $data);
}
}
You can also use
assertArraySubset()
from: https://phpunit.de/manual/current/en/appendixes.assertions.html#appendixes.assertions.assertArraySubset
another solution is to compare arrays and then check if true:
$arrays_are_equal = ($array1 == $array2); // or === if you want identical
$this->assertTrue($arrays_are_equal);
Another option is to test only the first element of the multidimensional Array, like this:
$this->assertArrayHasKey('idr', $testdata[0]);
$this->assertArrayHasKey('rel', $testdata[0]);
I believe that that control is not going inside the foreach loop.
Remove whole :
$testdata= Array
(
[0] => Array
(
[label] => 'Ammy'
[idr] => 'user7'
[rel] => 7
)
[1] => Array
(
[label] => 'sidh'
[idr] => user8
[rel] => 8
)
[2] => Array
(
[label] => 'Alan'
[idr] => 'user9'
[rel] => 9
)
)

Resources