XCART-5 Get Attributes Values in programming and Assigning some other values progmatically - x-cart

I am working on Xcart-5 website customization. And I created my own module and doing work on that. I just created some Global Attributes (" As a Plain text ") field and assign these attributes to some product. Now I want to access these fields value in programming in the product details page for assigning some other value programatically at run time.
How can I achieve this task. Kindly provide me the solution .

In your module you should decorate the \XLite\Model\Attribute class and extend the getAttributeValue() method there.
For instance, if I use a module with developer ID Tony and module ID AttributesDemo, then I would need to create the XCartDirectory/classes/XLite/Module/Tony/AttributesDemo/Model/Attribute.php file with the following content:
<?php
// vim: set ts=4 sw=4 sts=4 et:
namespace XLite\Module\Tony\AttributesDemo\Model;
/**
* Attribute
* #MappedSuperClass
*/
abstract class Attribute extends \XLite\Model\AttributeAbstract implements \XLite\Base\IDecorator
{
public function getAttributeValue(\XLite\Model\Product $product, $asString = false)
{
$result = parent::getAttributeValue($product, $asString);
if (!$asString) {
foreach ($result as $obj) {
if ($obj->asString() == 'Mac') {
$obj->getAttributeOption()->setName('Windows');
}
}
}
return $result;
}
}
Such implementation will change Mac values to Windows ones in all attributes.

Related

I am trying to alter route in my custon module. But it is already overridden in one of the contrib module

I tried to altered route it didn't work in my custom module. it is taking the altered path from contributed module. then i tried to extend the routesubscriber.php from extended module but its still didn't work.
I have cleared cache, rebuild routes, and tried to adjust weight for my custom module giving it highest weight. But still didn't work.
If anyone call help with this issue, it will be great help.
this is MyAppsRouteSubscriber.php
<?php
namespace Drupal\MyApps\Routing;
use Drupal\MyApps\Entity\ListBuilder\DeveloperAppListBuilder;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
use Drupal\apigee_kickstart_enhancement\Routing\RouteSubscriber;
/**
* Custom MyAppsRouteSubscriber for MyApps.
*/
class MyAppsRouteSubscriber extends RouteSubscriber
{
protected function alterRoutes(RouteCollection $collection)
{
// Override the controller for the Apigee Kickstart Enhancement.
/** #var \Drupal\Core\Entity\EntityTypeInterface $app_entity_type */
foreach (\Drupal::service('apigee_kickstart.enhancer')->getAppEntityTypes() as $entity_type_id => $app_entity_type) {
if ($route = $collection->get("entity.$entity_type_id.collection_by_" . str_replace('_app', '', $entity_type_id))) {
if ($entity_type_id == 'team_app') {
$route->setDefault('_controller', TeamAppListBuilder::class . '::render');
} else {
$route->setDefault('_controller', DeveloperAppListBuilder::class . '::render');
}
}
}
}
}
and i have DeveloperAppListBuilder.php
<?php
namespace Drupal\MyApps\Entity\ListBuilder;
use Drupal\apigee_edge\Entity\DeveloperAppRouteProvider;
use Drupal\apigee_edge\Entity\ListBuilder\DeveloperAppListBuilderForDeveloper;
/**
* Renders the Apps list as a list of entity views instead of a table.
*/
class DeveloperAppListBuilder extends DeveloperAppListBuilderForDeveloper
{
/**
* {#inheritdoc}
*/
public function render()
{
//code here
}
}
First make sure your module is following the details outlined in Naming and placing your Drupal 8 module - Name your module:
It must contain only lower-case letters and underscores.
The namespace in your details indicates it is using upper camel case instead of snake cases.
Also ensure your route subscriber has a relevant my_app.services.yml services YAML file and tag it with event_subscriber or it won't be registered:
services:
my_app.route_subscriber:
class: Drupal\my_app\Routing\MyAppsRouteSubscriber
tags:
- { name: event_subscriber }
Make sure your module is enabled or it won't be working either. Debug through it to see where it still fails.

Laravel 5 - global Blade view variable available in all templates

How can I in Laravel 5 make global variable which will be available in all Blade templates?
Option 1:
You can use view::share() like so:
<?php namespace App\Http\Controllers;
use View;
//You can create a BaseController:
class BaseController extends Controller {
public $variable1 = "I am Data";
public function __construct() {
$variable2 = "I am Data 2";
View::share ( 'variable1', $this->variable1 );
View::share ( 'variable2', $variable2 );
View::share ( 'variable3', 'I am Data 3' );
View::share ( 'variable4', ['name'=>'Franky','address'=>'Mars'] );
}
}
class HomeController extends BaseController {
//if you have a constructor in other controllers you need call constructor of parent controller (i.e. BaseController) like so:
public function __construct(){
parent::__construct();
}
public function Index(){
//All variable will be available in views
return view('home');
}
}
Option 2:
Use a composer:
Create a composer file at app\Composers\HomeComposer.php
NB: create app\Composers if it does not exists
<?php namespace App\Composers;
class HomeComposer
{
public function compose($view)
{
//Add your variables
$view->with('variable1', 'I am Data')
->with('variable2', 'I am Data 2');
}
}
Then you can attached the composer to any view by doing this
<?php namespace App\Http\Controllers;
use View;
class HomeController extends Controller{
public function __construct(){
View::composers([
'App\Composers\HomeComposer' => ['home'] //attaches HomeComposer to home.blade.php
]);
}
public function Index(){
return view('home');
}
}
Option 3:
Add Composer to a Service Provider, In Laravel 5 I prefer having my composer in App\Providers\ViewServiceProvider
Create a composer file at app\Composers\HomeComposer.php
Add HomeComposer to App\Providers\ViewServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use View;
use App\Composers\HomeComposer;
use Illuminate\Support\Facades\Blade;
class ViewServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//add to all views
view()->composer('*', HomeComposer::class);
//add to only home view
//view()->composer('home', HomeComposer::class);
}
}
Create a new Service Provider as suggested in here
Add your new Service Provider to the configuration file (config/app.php).
In the boot method of your new Service Provider use:
View::share( 'something_cool', 'this is a cool shared variable' );
Now you are ready to use $something_cool in all of your views.
Hope this helps.
Searching for solution of the same problem and found the best solution in Laravel documentation. Just use View::share in AppServiceProvider like this:
View::share('key', 'value');
Details here.
You can do this with view composers. View composers are executed when a template is loaded. You can pass in a Closure with additional functionality for that view. With view composers you can use wildcards. To make a view composer for every view just use a *.
View::composer('*', function($view)
{
$view->with('variable','Test value');
});
You can also do this without a closure as you can see in the docs.
View::composer('*', 'App\Http\ViewComposers\ProfileComposer');
The profile composer class must have a compose method.
View composers are executed when a view is rendered. Laravel has also view creators. These are executed when a view is instantiated.
You can also choose to use a BaseController with a setupLayout method. Then every view which you will load is loaded through the setupLayout method which adds some additional data. However, by using view composers you're pretty sure that the code is executed. But with the BaseController approach you've more flexibility because you can skip the loading of the extra data.
EDIT: As mentioned by Nic Gutierrez you can also use view share.
Also, you can do this in the Route.php file:
view()->share('variableName', $variable);
I would rather use middleware with the view() facade helper. (Laravel 5.x)
Middleware is easier to mantain and does not make a mess in the controllers class tree.
Steps
Create the Middleware
/app/Http/Middleware/TimezoneReset.php
To create a middleware you can run php artisan make:middleware GlobalTimeConfig
share() the data you need shared
<?php
namespace App\Http\Middleware;
use Closure;
class GlobalTimeConfig
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$time_settings = [
'company_timezone' => 'UTC',
'company_date_format' => 'Y-m-d H:i:s',
'display_time' => true,
];
view()->share('time_settings', $time_settings);
return $next($request);
}
}
Register the newly created middleware
Add the middleware to your middleware route group as per example below
/app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\GlobalTimeConfig::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
Access data from templates
Access the data from any template with the given key in the View::share() method call
eg.:
Company timezone: {{ $time_settings['company_timezone'] }}
EDIT:
Nic Gutierrez's Service Provider answer might be a better (or the best) solution.
and you can give array not just View::share('key', 'value');
can put array like View::share(['key'=>'value','key'=>'value'])
You can add in Controller.php file:
use App\Category;
And then:
class Controller extends BaseController {
public function __construct() {
$categories = Category::All();
\View::share('categories', $categories);
}
}
you can flash it into the session, you can define it in the .env file (static vars)

OpenCart pass data to children module

Basically what i'm trying to do is to pass some data from "parent" controller to the controller of its children module, for example:
header controller
$this->children = array(
'module/newslettersubscribe'
);
newslettersubscribe controller
public function index() {
// Use here data from the header controller
}
Is that even possible to do?
Here the approach is incorrect. You should edit only the slider controller and check whether there is a path variable available in the GET (query string), e.g.:
if (!empty($this->request->get['path'])) { /* ... */ }
If it is you can now extract the categories from it's value (which is e.g. 1_12_36):
if (!empty($this->request->get['path'])) {
$category_ids = explode('_', (string)$this->request->get['path']);
}
Now knowing the category IDs (or the category path) you can display the appropriate images only using whatever code you made up.

Ignore a Doctrine2 Entity when running schema-manager update

I've got a Doctrine Entity defined that maps to a View in my database. All works fine, the Entity relations work fine as expected.
Problem now is that when running orm:schema-manager:update on the CLI a table gets created for this entity which is something I want to prevent. There already is a view for this Entity, no need to create a table for it.
Can I annotate the Entity so that a table won't be created while still keeping access to all Entity related functionality (associations, ...)?
Based on the original alswer of ChrisR inspired in Marco Pivetta's post I'm adding here the solution if you're using Symfony2:
Looks like Symfony2 doesn't use the original Doctrine command at:
\Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand
Instead it uses the one in the bundle:
\Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand
So basically that is the class that must be extended, ending up in having:
src/Acme/CoreBundle/Command/DoctrineUpdateCommand.php:
<?php
namespace App\Command;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Tools\SchemaTool;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class DoctrineUpdateCommand extends UpdateSchemaDoctrineCommand
{
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas, SymfonyStyle $ui): ?int
{
$ignoredEntities = [
'App\Entity\EntityToIgnore',
];
$metadatas = array_filter($metadatas, static function (ClassMetadata $classMetadata) use ($ignoredEntities) {
return !in_array($classMetadata->getName(), $ignoredEntities, true);
});
return parent::executeSchemaCommand($input, $output, $schemaTool, $metadatas, $ui);
}
}
Eventually it was fairly simple, I just had to subclass the \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand into my own CLI Command. In that subclass filter the $metadatas array that's being passed to executeSchemaCommand() and then pass it on to the parent function.
Just attach this new subclassed command to the ConsoleApplication you are using in your doctrine cli script and done!
Below is the extended command, in production you'll probably want to fetch the $ignoredEntities property from you config or something, this should put you on the way.
<?php
use Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand;
use Doctrine\ORM\Tools\SchemaTool;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class My_Doctrine_Tools_UpdateCommand extends UpdateCommand
{
protected $name = 'orm:schema-tool:myupdate';
protected $ignoredEntities = array(
'Entity\Asset\Name'
);
protected function executeSchemaCommand(InputInterface $input, OutputInterface $output, SchemaTool $schemaTool, array $metadatas, SymfonyStyle $ui)
{
/** #var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
$newMetadata = [];
foreach ($metadatas as $metadata) {
if (!in_array($metadata->getName(), $this->ignoredEntities)) {
$newMetadata[] = $metadata;
}
}
return parent::executeSchemaCommand($input, $output, $schemaTool, $newMetadata, $ui);
}
}
PS: credits go to Marco Pivetta for putting me on the right track. https://groups.google.com/forum/?fromgroups=#!topic/doctrine-user/rwWXZ7faPsA
Quite old one but there is also worth nothing solution using Doctrine2: postGenerateSchema event listener - for me it's better than overriding
Doctrine classes:
namespace App\Doctrine\Listener;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
/**
* IgnoreTablesListener class
*/
class IgnoreTablesListener
{
private $ignoredTables = [
'table_name_to_ignore',
];
public function postGenerateSchema(GenerateSchemaEventArgs $args)
{
$schema = $args->getSchema();
$tableNames = $schema->getTableNames();
foreach ($tableNames as $tableName) {
if (in_array($tableName, $this->ignoredTables)) {
// remove table from schema
$schema->dropTable($tableName);
}
}
}
}
Also register listener:
# config/services.yaml
services:
ignore_tables_listener:
class: App\Doctrine\Listener\IgnoreTablesListener
tags:
- {name: doctrine.event_listener, event: postGenerateSchema }
No extra hooks is necessary.
In Doctrine 2.7.0 it was introduced the new SchemaIgnoreClasses entity manager config option that basically ignores the configured classes from any schema action.
To use it with Symfony we only need to add the schema_ignore_classes key in the Doctrine entity manager configuration like this:
doctrine:
dbal:
# your dbal configuration
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Main'
prefix: 'App\Entity\Main'
alias: Main
schema_ignore_classes:
- Reference\To\My\Class
- Reference\To\My\OtherClass
$schema->getTableNames() was not working (I don't know why).
So:
<?php
namespace AppBundle\EventListener;
use Doctrine\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
class IgnoreTablesListener extends UpdateSchemaDoctrineCommand
{
private $ignoredEntities = [
'YourBundle\Entity\EntityYouWantToIgnore',
];
/**
* Remove ignored tables /entities from Schema
*
* #param GenerateSchemaEventArgs $args
*/
public function postGenerateSchema(GenerateSchemaEventArgs $args)
{
$schema = $args->getSchema();
$em = $args->getEntityManager();
$ignoredTables = [];
foreach ($this->ignoredEntities as $entityName) {
$ignoredTables[] = $em->getClassMetadata($entityName)->getTableName();
}
foreach ($schema->getTables() as $table) {
if (in_array($table->getName(), $ignoredTables, true)) {
// remove table from schema
$schema->dropTable($table->getName());
}
}
}
}
And Register a service
# config/services.yaml
services:
ignore_tables_listener:
class: AppBundle\EventListener\IgnoreTablesListener
tags:
- {name: doctrine.event_listener, event: postGenerateSchema }
Worked fine! ;)
If problem is only with producing errors in db_view, when calling doctrine:schema:update command, why not simplest way:
remove # from #ORM\Entity annotation
execute doctrine:schema:update
add # to ORM\Entity annotation
;-)

Zend Framework 2 - Doctrine 2 Error message

I have been trying to add more flexibilities to the Album Module from Zend Framework 2. In that process I have been trying to set a validator for one of the form fields especially for the album name which in my case the column name in my database is title.
I have been following the validation part from one of the previous answers to my post, which can be found here
I have been using that class in my albumcontroller class in this fashion:
<?php
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Album\Entity\Album\Album;
use Album\Form\AlbumForm;
use Album\Model\Album\AlbumExists;
use Doctrine\ORM\EntityManager;
class AlbumController
extends AbstractActionController
{
public function addAction()
{
$form = new AlbumForm();
$form->get('submit')->setAttribute('value', 'Add');
$query = "SELECT a.title FROM Album\Entity\Album\Album a";
$albumExists = new AlbumExists($this->getEntityManager(), $query, 'title');
$request = $this->getRequest();
if ($request->isPost())
{
$album = new Album();
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
$title = $this->getRequest()->getPost('title');
if ($form->isValid() && $albumExists->isValid($title))
{
$album->populate($form->getData());
$this->getEntityManager()->persist($album);
$this->getEntityManager()->flush();
return $this->redirect()->toRoute('album');
}
}
return array('form' => $form);
}
When I enter a album name/title which is already in the database it throws an error in this fashion:
An error occurred during execution; please try again later.
Additional information:
Doctrine\ORM\Query\QueryException
File:
C:\vendor\doctrine\orm\lib\Doctrine\ORM\Query\QueryException.php:69
Message:
Invalid parameter number: number of bound variables does not match number of tokens.
Any idea where Im making a mistake?
In case you're using "my" class and haven't modified that part, you're missing the WHERE condition in your query.
In the class, a parameter :value is bound, so you have to use this parameter in your query (e.g. WHERE a.title = :value).