Unable to set attribute with bless method - raku

Got a weird situation I think might be a bug. Not sure. But I have this:
class Y {
has Int $.vol;
has Str $.quant;
has Str $.abbr;
submethod BUILD(
Str :$!abbr,
Int :$!vol,
) { }
}
class X is Y {
multi method new(Int:D :$vol) {
self.bless(
:$vol,
:abbr('C'),
);
}
multi method new(Str:D :$quant) {
self.bless(
:$quant,
:abbr('C'),
);
}
}
my $x = X.new(vol => 7);
say $x;
# OUTPUT: X.new(vol => 7, abbr => "C")
This works as expected. The abbr attribute is populated. However, in the code below, I can't get the abbr to populate:
#!/usr/bin/env raku
use v6.d;
use Lingua::EN::Numbers;
constant Nᴀ = 602214076000000000000000;
class Mass-t { ... }
class Mass-kg { ... }
class Mass-g { ... }
class Mass-mg { ... }
class Mass-ug { ... }
class Mass-mcg { ... }
class Mass-oz { ... }
class Mass-lb { ... }
class Mass-c { ... }
class Volume-m { ... }
class Volume-cm { ... }
class Volume-mm { ... }
class Length-cm { ... }
class Length-m { ... }
class Length-mm { ... }
class Quantity-mol { ... }
class Quantity-dz { ... }
class Substance-c { ... }
class Substance-air { ... }
class Volume { ... }
END {
my $v = Quantity-mol.new(1.0);
my $c = Substance-c.new(quant => $v);
say $c;
say 'done with program';
exit;
}
class Quantity {
has Str $.name;
has Str $.abbr is rw;
has Rat $.value;
has Rat $.base_value;
submethod BUILD(Rat :$!value,
Str :$!name,
Str :$!abbr,
Rat :$!base_value,
) { }
method get_value() {
return $!value ~ ' ' ~ $!abbr;
}
method count(Bool:D $comma = True) {
return comma $!value * $!base_value if $comma;
return $!value * $!base_value;
}
method to(Str:D $abbr-in) {
my $class = split('-', self.^name)[0];
my $abbr = $abbr-in.lc;
my $to = ::("$class-$abbr").new();
self!convert($to);
}
method !convert(Quantity:D $to) {
my $result = comma (self.count(False) / $to.base_value);
return $result ~ ' ' ~ $to.abbr;
}
}
class Quantity-mol is Quantity {
method new(Rat:D() $value = 1.0) {
self.bless(
:name('mole'),
:abbr('㏖'),
:base_value(Rat.new(Nᴀ, 1)),
:$value,
);
}
}
class Quantity-dz is Quantity {
method new(Rat:D() $value = 1.0) {
self.bless(
:base_value(12.0),
:name('dozen'),
:abbr('dz'),
:$value,
);
}
}
class Measure {
has Str $!name;
has Str $.abbr is rw;
has Rat $.value;
has Rat $.base_value;
has Rat $.imp_base_value;
submethod BUILD(Rat :$!value,
Str :$!name,
Str :$!abbr,
Rat :$!base_value,
Rat :$!imp_base_value,
) { }
method to(Str:D $abbr-in) {
my $class = split('-', self.^name)[0];
my $abbr = $abbr-in.lc;
my $to = ::("$class-$abbr").new();
self!convert($to)
}
method !convert(Measure:D $to) {
my $imp_conv = $.imp_base_value && $to.imp_base_value;
my $base_value = $imp_conv ?? $.imp_base_value !! $.base_value;
my $to_base_value = $imp_conv ?? $to.imp_base_value !! $to.base_value;
my $conversion = ($.value * $base_value) / $to_base_value;
my $num = $conversion > 1 ?? comma ($conversion) !! $conversion < 1/10000 ?? (sprintf "%.5e", $conversion) !! $conversion;
# do pretty scientific notation
if $conversion < 1 / 10000 {
my $exp = $num ~~ / '-' 0* <(\d+)>$/;
$exp .= trans( '0123456789' => '⁰¹²³⁴⁵⁶⁷⁸⁹' );
$num .= subst(/e\-\d+/, "\x[00D7]10\x[207B]$exp");
}
return $num ~ ' ' ~ $to.abbr;
}
method !count {
}
}
class Mass is Measure { }
class Length is Measure { }
class Substance {
has Quantity-mol $.quant;
has Volume $.vol;
has Str $.abbr is rw;
submethod BUILD(Quantity-mol :$!quant,
Volume :$!vol,
Str :$!abbr,
) { }
method volume() {
return $.vol.value ~ ' ' ~ $.vol.abbr;
}
method moles() {
return $.quant.value ~ ' ' ~ $.quant.abbr ~ ' ' ~ $.abbr;
}
}
class Substance-co2 is Substance {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('cm'),
:$value,
);
}
}
class Substance-c is Substance {
multi method new(Volume:D $vol) {
self.bless(
:$vol,
:abbr('C'),
);
}
multi method new(Quantity-mol:D $quant) {
self.bless(
:$quant,
:abbr('C'),
);
}
}
class Substance-air is Substance {
}
class Length-cm is Length {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('cm'),
:base_value(1/100),
:$value,
);
}
}
class Length-m is Length {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('m'),
:base_value(1.0),
:$value,
);
}
}
class Length-mm is Length {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('mm'),
:base_value(1/1000),
:$value,
);
}
}
class Volume is Measure {
has Str $.abbr;
has Rat $.base_value;
has Rat $.value;
}
class Volume-m is Volume {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('m³'),
:base_value(1.0),
:$value,
);
}
}
class Volume-cm is Volume {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('cm³'),
:base_value(1 / 1_000_000),
:$value,
);
}
}
class Volume-l is Volume {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('l'),
:base_value(1 / 1_000),
:$value,
);
}
}
class Volume-ml is Volume {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('ml'),
:base_value(1 / 1_000_000),
:$value,
);
}
}
class Volume-mm is Volume {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('mm³'),
:base_value(1 / 1_000_000_000),
:$value,
);
}
}
class Density {
has Mass $.mass;
has Volume $.volume;
method calculate() {
return $.mass / $.volume;
}
}
class Density-water {
method new(Rat:D()) {
self.bless(
:mass(Mass-kg.new()),
:volume(Volume-l.new()),
);
}
}
class Mass-c is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('g/mol'),
:base_value(12.0107),
:$value,
);
}
}
class Mass-air is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('g/mol'),
:base_value(28.9647),
:$value,
);
}
}
class Mass-Da is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('Da'),
:base_value(Rat.new(1, 602214075789225073400000)),
:$value,
);
}
}
class Mass-kg is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('kg'),
:base_value(1000.0),
:$value,
);
}
}
class Mass-oz is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('oz'),
:base_value(28.3495231),
:imp_base_value(1/16),
:$value,
);
}
}
class Mass-lb is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('lb'),
:base_value(453.59237),
:imp_base_value(1.0),
:$value,
);
}
}
# lb aliases
class Mass-g is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('g'),
:base_value(1.0),
:$value,
);
}
}
class Mass-mg is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('mg'),
:base_value(1/1000),
:$value,
);
}
}
class Mass-ug is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('µg'),
:base_value(1/1_000_000),
:$value,
);
}
}
class Mass-mcg is Mass-ug {
method TWEAK { $.abbr = "mcg" }
}
class Mass-mt is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('mt'),
:base_value(1_000_000.0),
:$value,
);
}
}
class Mass-gt is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('mt'),
:base_value(1_000_000_000_000.0),
:$value,
);
}
}
class Mass-t is Mass {
method new(Rat:D() $value = 1.0) {
self.bless(
:abbr('t'),
:base_value(907184.74),
:$value,
);
}
}
This outputs:
Substance-c.new(quant => Quantity-mol.new(name => "mole", abbr => "㏖", value => 1.0, base_value => 602214076000000000000000.0), vol => Volume, abbr => Str)
Note here the abbr attribute never gets set. It's just says Str (be sure to scroll all the way to the right to see this). I've been staring at this for a long time and cannot figure it out what's going on.

To get answers on SO, it would help if you would golf your code to be as small as possible.
Anyways, the problem is really in the way that you try to create the Substance object.
my $c = Substance-c.new(quant => $v);
You created a new candidate in Substance-c with a positional:
multi method new(Quantity-mol:D $quant) {
self.bless(
:$quant,
:abbr('C'),
);
}
So if you change the call to:
my $c = Substance-c.new($v);
you are in business.
So why doesn't this create an error? That's because the way you called it, uses the default new (provided by the system), which only takes named arguments. So it was not calling any of the new methods you provided.
One further note: why all the BUILD methods? None of them are needed in your example, as far as I can see.

Related

How can I create a factory for classes? Getting "undeclared name" error

I have this code:
class kg is Dimension {
method new() {
return self.bless(
:type('mass'),
:abbr('kg'),
:multiplier(Multiplier.new(
numerator => 1.0,
denominator => Quantity.new(1000.0, 'g')))),
}
}
class mg is Dimension {
method new() {
return self.bless(
:type('mass'),
:abbr('mg'),
:multiplier(Multiplier.new(
numerator => 1000.0,
denominator => Quantity.new(1.0, 'g')))),
}
}
I'll be adding many more similar classes. Rather than spell out all these classes separately, I'd like to learn how to create a factory that can create these classes from simple data structures.
How do I do this? I read the Metaobject Protocol doc but I couldn't figure out how to give my classes different names on the fly based on the examples at the top and middle of the doc page.
I tried:
constant A := Metamodel::ClassHOW.new_type( name => 'A' );
A.^add_method('x', my method x(A:) { say 42 });
A.^add_method('set', my method set(A: Mu \a) { A.^set_name(a) });
A.^compose;
my $bar = A;
$bar.set('Foo');
say $bar.^name; #
A.x; # works
Foo.x; # error
But the last line just throws an error:
Undeclared name:
Foo used at line 13
The first thing you should realize, that any kind of meta-programmming usually will need to be done at compile time, aka in a BEGIN block.
Secondly: at the moment, Raku has some meta-programming features for creating code, but not all features needed to make this as painless as possible. The work on RakuAST will change that, as it basically makes Raku itself being built from a public meta-programming API (rather than you could argue, the current bootstrap version using a lot of NQP).
I've rewritten your code to the following:
sub frobnicate(Str:D $name) {
my \A := Metamodel::ClassHOW.new_type(:$name);
A.^add_method('x', my method x() { say 42 });
A.^compose;
OUR::{$name} := A;
}
BEGIN frobnicate("Foo");
say Foo.^name; # Foo
Foo.x; # 42
So, this introduces a sub called frobnicate that creates a new type with the given name. Adds a method x to it, and composes the new type. And then makes sure it is known as an our in the current compilation unit.
Then the frobnicate sub is called at compile time by prefixing a BEGIN. This is important, because otherwise Foo won't be known when the next line is compiled, so you'd get errors.
There is currently a small catch:
dd Foo.^find_method("x").signature; # :(Mu: *%_)
The invocant constraint is not set. I haven't found a way (before RakuAST) to set that using an meta-programming interface. But I don't think that's going to be an issue for the example you've given. If it does become an issue, then let's cross that bridge when we get there.
Here is the entire code that I came up with for a solution:
#!/usr/bin/env raku
use v6.d;
class Dimension { }
sub dimension-attr-factory($name, Mu $type, Mu $package) {
return Attribute.new(
:name('$.' ~ $name),
:type($type),
:has_accessor(1),
#:is_required(1),
:package($package)
);
}
sub dimension-factory(Str:D $name, #attributes) {
my \A := Metamodel::ClassHOW.new_type(:$name);
A.^add_parent(Dimension);
for #attributes {
my $attr = dimension-attr-factory($_[0], $_[1], A);
A.^add_attribute($attr);
}
A.^compose;
OUR::{$name} := A;
}
class Multiplier {
has Rat $.numerator;
has Quantity $.denominator;
method factor() {
return $.numerator / $.denominator.value;
}
}
class Quantity {
has Rat() $.value is required;
has Dimension:D $.dimension is required;
multi submethod BUILD(Rat:D() :$!value, Dimension:D :$!dimension) {
}
multi submethod BUILD(Rat:D() :$value, Str:D :$dimension) {
$!dimension = ::($dimension).new;
}
multi method new(Rat:D() $value, Dimension:D $dimension) {
return self.bless(
:$value,
:$dimension,
)
}
multi method new(Rat:D() $value, Str:D $dimension) {
return self.bless(
:$value,
:$dimension,
)
}
method to(Str:D $dimension = '') {
my $from_value = $.value;
my $to = $dimension ?? ::($dimension).new !! ::(self.dimension.abbr).new;
# do types match?
if $to.type ne self.dimension.type {
die "Cannot convert a " ~ self.dimension.type ~ " to a " ~ $to.type;
};
my $divisor = $.dimension.multiplier ?? $.dimension.multiplier.factor !! 1.0;
my $dividend = $to.multiplier ?? $to.multiplier.factor !! 1;
my $result = $dividend / $divisor * $from_value;
return Quantity.new($result, $to);
}
method gist() {
$.value ~ ' ' ~ $.dimension.abbr;
}
}
BEGIN {
my %dimensions = 'mass' => {
base => {
abbr => 'g',
},
derived => {
kg => { num => 1000.0, den => 1.0, },
mg => { num => 1.0, den => 1000.0, },
ug => { num => 1.0, den => 1000000.0, },
}
};
for %dimensions.kv -> $key, $value {
# set up base class for dimension type
my $base = %dimensions{$key}<base><abbr>;
my #attributes = ['abbr', $base], ['type', $key];
dimension-factory( $base, #attributes);
my %derived = %dimensions{$key}<derived>;
for %derived.kv -> $abbr, $values {
my $numerator = %dimensions{$key}<derived>{$abbr}<num>;
my $denominator = %dimensions{$key}<derived>{$abbr}<den>;
my $multiplier = Multiplier.new(
numerator => 1.0,
denominator => Quantity.new(1000.0, 'g'),
);
#attributes = ['abbr', $abbr], ['type', $key], ['multiplier', $multiplier];
my $dim = dimension-factory( $abbr, #attributes );
#$dim.new(:$abbr, type => $key, :$multiplier );
}
}
}
my $kg = kg.new();
my $quant = Quantity.new(value => 5.0, dimension => $kg);
dd $quant;
I would probably create a dimension keyword with a custom metamodel, would probably also override * and / operators using undefined dimensions and then would create kg with something like:
dimension Gram {
has Dimension::Type $.type = mass;
has Str $.abbr = "g";
}
dimension KiloGram is Gram {
has Str $.abbr = "kg";
has Dimension::Multiplier $.multiplier = 1000 * g;
}
dimension MiliGram is Gram {
has Str $.abbr = "mg";
has Dimension::Multiplier $.multiplier = g / 1000;
}
but maybe that's too much...

Can Uncrustify be configured to align braces in one-line functions in header files?

Scenario: C++, a bunch of one-line setters and getters inlined in the header file, as follows:
bool hasVoices(int staffIdx) const { return m_mstaves[staffIdx]->hasVoices(); }
void setHasVoices(int staffIdx, bool v) { return m_mstaves[staffIdx]->setHasVoices(v); }
StaffLines* staffLines(int staffIdx) { return m_mstaves[staffIdx]->lines(); }
Spacer* vspacerDown(int staffIdx) const { return m_mstaves[staffIdx]->vspacerDown(); }
Spacer* vspacerUp(int staffIdx) const { return m_mstaves[staffIdx]->vspacerUp(); }
void setStaffVisible(int staffIdx, bool visible) { m_mstaves[staffIdx]->setVisible(visible); }
void setStaffStemless(int staffIdx, bool stemless) { m_mstaves[staffIdx]->setStemless(stemless); }
bool corrupted(int staffIdx) const { return m_mstaves[staffIdx]->corrupted(); }
void setCorrupted(int staffIdx, bool val) { m_mstaves[staffIdx]->setCorrupted(val); }
MeasureNumber* noText(int staffIdx) const { return m_mstaves[staffIdx]->noText(); }
void setNoText(int staffIdx, MeasureNumber* t) { m_mstaves[staffIdx]->setNoText(t); }
MeasureNumberMode measureNumberMode() const { return m_noMode; }
void setMeasureNumberMode(MeasureNumberMode v) { m_noMode = v; }
Fraction timesig() const { return m_timesig; }
void setTimesig(const Fraction& f) { m_timesig = f; }
bool isIrregular() const { return m_timesig != _len; }
int size() const { return m_segments.size(); }
Segment* first() const { return m_segments.first(); }
Segment* first(SegmentType t) const { return m_segments.first(t); }
Segment* firstEnabled() const { return m_segments.first(ElementFlag::ENABLED); }
Segment* last() const { return m_segments.last(); }
SegmentList& segments() { return m_segments; }
const SegmentList& segments() const { return m_segments; }
void setUserStretch(qreal v) { m_userStretch = v; }
The function bodies are aligned for the sake of readability. The repository I'm contributing to has just begun using Uncrustify and added a test to enforce the code style for new pull requests. Uncrustify as currently configured wants this changed to:
bool hasVoices(int staffIdx) const { return m_mstaves[staffIdx]->hasVoices(); }
void setHasVoices(int staffIdx, bool v) { return m_mstaves[staffIdx]->setHasVoices(v); }
StaffLines* staffLines(int staffIdx) { return m_mstaves[staffIdx]->lines(); }
Spacer* vspacerDown(int staffIdx) const { return m_mstaves[staffIdx]->vspacerDown(); }
Spacer* vspacerUp(int staffIdx) const { return m_mstaves[staffIdx]->vspacerUp(); }
void setStaffVisible(int staffIdx, bool visible) { m_mstaves[staffIdx]->setVisible(visible); }
void setStaffStemless(int staffIdx, bool stemless) { m_mstaves[staffIdx]->setStemless(stemless); }
bool corrupted(int staffIdx) const { return m_mstaves[staffIdx]->corrupted(); }
void setCorrupted(int staffIdx, bool val) { m_mstaves[staffIdx]->setCorrupted(val); }
MeasureNumber* noText(int staffIdx) const { return m_mstaves[staffIdx]->noText(); }
void setNoText(int staffIdx, MeasureNumber* t) { m_mstaves[staffIdx]->setNoText(t); }
MeasureNumberMode measureNumberMode() const { return m_noMode; }
void setMeasureNumberMode(MeasureNumberMode v) { m_noMode = v; }
Fraction timesig() const { return m_timesig; }
void setTimesig(const Fraction& f) { m_timesig = f; }
bool isIrregular() const { return m_timesig != _len; }
int size() const { return m_segments.size(); }
Segment* first() const { return m_segments.first(); }
Segment* first(SegmentType t) const { return m_segments.first(t); }
Segment* firstEnabled() const { return m_segments.first(ElementFlag::ENABLED); }
Segment* last() const { return m_segments.last(); }
SegmentList& segments() { return m_segments; }
const SegmentList& segments() const { return m_segments; }
void setUserStretch(qreal v) { m_userStretch = v; }
Can Uncrustify be configured to produce something more like the first example instead?
You can use:
# Don't split one-line function definitions, as in 'int foo() { return 0; }'.
# might modify nl_func_type_name
nl_func_leave_one_liners = true # true/false
But that won't help you with the spacing for cases where you have a const in your member function. Open up a bug ticket and well see what we can do about that / point you in the directions to create a PR for that.

PDO: My DELETE statement in the User->logout() is not executing

my errors:
Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* FROM tbl_usersession WHERE BenutzerID = ?' at line 1 in C:\xampp7-4-3\htdocs\Corona\classes\db.php:52 Stack trace: #0 C:\xampp7-4-3\htdocs\Corona\classes\db.php(52): PDO->prepare('DELETE * FROM t...') #1 C:\xampp7-4-3\htdocs\Corona\classes\db.php(94): DB->query('DELETE * FROM t...', Array) #2 C:\xampp7-4-3\htdocs\Corona\classes\db.php(111): DB->action('DELETE *', 'tbl_usersession', Array) #3 C:\xampp7-4-3\htdocs\Corona\classes\user.php(135): DB->delete('tbl_usersession', Array) #4 C:\xampp7-4-3\htdocs\Corona\logout.php(5): User->logout() #5 {main} thrown in C:\xampp7-4-3\htdocs\Corona\classes\db.php on line 52
the code:
<?php
require_once 'core/init.php';
$user = new User();
$user->logout();
// Redirect::to('index.php');
?>
my user class:
<?php
class User
{
private $_db,
$_data,
$_sessionName,
$_cookieName,
$_isLoggedIn;
public function __construct($user = null)
{
$this->_db = DB::getInstance();
$this->_sessionName = Config::get('session/session_name');
$this->_cookieName = Config::get('remember/cookie_name');
if(!$user)
{
if(Session::exists($this->_sessionName))
{
$user = Session::get($this->_sessionName);
if($this->find($user))
{
$this->_isLoggedIn = true;
}
else
{
//process logout
}
}
}
else
{
$this->find($user);
}
}
public function create($fields = array())
{
if
(
$this->_db->insert('tbl_benutzer', $fields)
)
{
throw new Exception('Es gab einen Fehler bei der Erstellung Ihres Kontos.');
}
echo "Ihr Benutzerkonto wurde erfolgreich angelegt. Sie können sich jetzt anmelden.";
}
public function find($email = null)
{
if($email)
{
$field = (is_numeric($email)) ? 'id' : 'Email';
$data = $this->_db->get('tbl_benutzer', array($field, '=', $email));
if($data->count())
{
$this->_data = $data->first();
return true;
}
return false;
}
}
public function login($email = null, $password = null, $remember = false)
{
// echo "Remember=" . $remember . "<br>";
$user = $this->find($email);
if(!$email && !$password && $this->exists())
{
Session::put($this->_sessionName, $this->data()->ID);
}
else
{
$user = $this->find($email);
if($user)
{
if(password_verify($password, $this->data()->Hash))
{
Session::put($this->_sessionName, $this->data()->ID);
echo "Remember=" . $remember . "<br>";
if($remember)
{
$hash = Hash::unique();
echo "Hash=" . $hash . "<br>";
echo "id=" . $this->data()->ID . "<br>";
$hashCheck = $this->_db->get('tbl_usersession', array('BenutzerID', "=", $this->data()->ID));
echo "HashCheckCount= " . $hashCheck->count() . "<br>";
if(!$hashCheck->count())
{
$this->_db->insert
(
'tbl_usersession',
array
(
'BenutzerID' => $this->data()->ID,
'Hash' => $hash
)
);
}
else
{
$hash = $hashCheck->first()->Hash;
}
}
Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry'));
return true;
}
else return false;
}
}
return false;
}
public function exists()
{
return (!empty($this->data)) ? true : false;
}
public function logout()
{
$this->_db->delete('tbl_usersession', array('BenutzerID', '=', $this->data()->ID));
print_r($this->data());
// Wieso geht das delete nicht?
Session::delete($this->_sessionName);
Cookie::delete($this->_cookieName);
}
public function data()
{
return $this->_data;
}
public function isLoggedIn()
{
return $this->_isLoggedIn;
}
}
?>
my db class:
<?php
class DB
{
private static $_instance = null;
private $_pdo,
$_query,
$_error = false,
$_results,
$_count = 0;
private function __construct()
{
try
{
$this->_pdo = new PDO
(
'mysql:host=' . Config::get('mysql/host') . ';dbname=' . Config::get('mysql/db'),
Config::get('mysql/username'),
Config::get('mysql/password')
);
// Error tracking:
$this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch
(
PDOException $e
)
{
die($e->getMessage());
}
}
public static function getInstance()
{
if
(
!isset(self::$_instance)
)
{
self::$_instance = new DB();
}
return self::$_instance;
}
public function query($sql, $params = array())
{
$this->_error = false;
if($this->_query = $this->_pdo->prepare($sql))
{
$x = 1;
if(count($params))
{
foreach($params as $param)
{
$this->_query->bindValue($x, $param);
$x++;
}
}
if($this->_query->execute())
{
$this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
$this->_count = $this->_query->rowCount();
}
else
{
$this->_error = true;
}
}
return $this;
}
public function action($action, $table, $where = array())
{
if(count($where) === 3)
{
$operators = array('=', '<', '>', '<=', '>=');
$field = $where[0];
$operator = $where[1];
$value = $where[2];
if(in_array($operator, $operators))
{
$sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
if($this->query($sql, array($value)))
{
return $this;
}
}
}
return false;
}
public function get($table, $where)
{
return $this->action('SELECT *', $table, $where);
}
public function delete($table, $where)
{
return $this->action('DELETE *', $table, $where);
}
public function insert($table, $fields = array())
{
if
(
count($fields)
)
{
$keys = array_keys($fields);
$values = null;
$x = 1;
foreach($fields as $field)
{
$values .= '?';
if
(
$x < count($fields)
)
{
$values .= ', ';
}
$x++;
}
$sql = "INSERT INTO " . $table . " (" . implode(", ", $keys) . ") VALUES ({$values})";
if
(
$this->query($sql, $fields)->error()
)
{
return true;
}
}
}
public function update($table, $id, $fields = array())
{
$set = ' ';
$x = 1;
foreach
(
$fields as $name => $value
)
{
$set .= "{$name} = ?";
if
(
$x < count($fields)
)
{
$set .= ', ';
}
$x++;
}
$sql = "UPDATE {$table} SET {$set} WHERE ID = {$id}";
if
(
$this->query($sql, $fields)->error()
)
{
return true;
}
return false;
}
public function results()
{
return $this->_results;
}
public function first()
{
return $this->results()[0];
}
public function error()
{
return $this->_error;
}
public function count()
{
return $this->_count;
}
}
?>
It just basic syntax error for DELETE Statement shown as below:
The correct syntax is
DELETE FROM table
But your wrong syntax is
DELETE * FROM table
So debug your delete function will be solved your syntax error
public function delete($table, $where)
{
return $this->action('DELETE', $table, $where);
}

How to move the snap position from center to left of RecycleView using SnapHelper?

I have an RecycleView that contains ImageViews and my question is how can i move the snap to be on the left side of the RecycleView instead of the center?
When i move the ImageViews they get snapped in the center and I can move them to the left or right inside that "snap window" by overriding the CalculateDistanceToFinalSnap method. I think I would now need to move that "snap window" to the left side of the RecycleView but I don't know how, or maybe there is another way, please help.
Here is a image of my problem, maybe it will help you to understand more clearly:
image
#Jessie Zhang -MSFT's solution works for me. The code was a little oddly formatted and I had some difficulty bringing it over. Here is the same solution (for a horizontal snap only) in Kotlin.
class StartSnapHelper: LinearSnapHelper() {
override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray? {
return if (layoutManager.canScrollHorizontally()) {
val outer = mutableListOf<Int>()
outer.add(distanceToStart(targetView, getHorizontalHelper(layoutManager)))
outer.add(0)
outer.toIntArray()
} else {
super.calculateDistanceToFinalSnap(layoutManager, targetView)
}
}
override fun findSnapView(layoutManager: RecyclerView.LayoutManager?): View? {
return if (layoutManager is LinearLayoutManager) {
if (layoutManager.canScrollHorizontally()) {
getStartView(layoutManager, getHorizontalHelper(layoutManager))
} else {
super.findSnapView(layoutManager)
}
} else {
super.findSnapView(layoutManager)
}
}
private fun distanceToStart(targetView: View, helper: OrientationHelper): Int {
return helper.getDecoratedStart(targetView) - helper.startAfterPadding
}
private fun getStartView(layoutManager: RecyclerView.LayoutManager, orientationHelper: OrientationHelper): View? {
val firstChild = (layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
val isLastItem = (layoutManager.findLastCompletelyVisibleItemPosition() == layoutManager.itemCount - 1)
if (firstChild == RecyclerView.NO_POSITION || isLastItem) {
return null
}
val child = layoutManager.findViewByPosition(firstChild)
return if (orientationHelper.getDecoratedEnd(child) >= orientationHelper.getDecoratedMeasurement(child) / 2
&& orientationHelper.getDecoratedEnd(child) > 0) {
child;
} else {
if (layoutManager.findFirstCompletelyVisibleItemPosition() == layoutManager.itemCount -1) {
null
} else {
layoutManager.findViewByPosition(firstChild + 1)
}
}
}
private fun getHorizontalHelper(layoutManager: RecyclerView.LayoutManager): OrientationHelper {
return OrientationHelper.createHorizontalHelper(layoutManager)
}
}
I have achieved this function ,we juse need to create a class and extent class LinearSnapHelper and override method CalculateDistanceToFinalSnap and FindSnapView. You can check out the full demo here .
The main code is as follows:
public class StartSnapHelper: LinearSnapHelper
{
private OrientationHelper mVerticalHelper, mHorizontalHelper;
public StartSnapHelper()
{
}
public override void AttachToRecyclerView(RecyclerView recyclerView)
{
base.AttachToRecyclerView(recyclerView);
}
public override int[] CalculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView)
{
//return base.CalculateDistanceToFinalSnap(layoutManager, targetView);
int[] outer = new int[2];
if (layoutManager.CanScrollHorizontally())
{
outer[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager));
} else {
outer[0] = 0;
}
if (layoutManager.CanScrollVertically()) {
outer[1] = distanceToStart(targetView, getVerticalHelper(layoutManager));
} else {
outer[1] = 0;
}
return outer;
}
private int distanceToStart(View targetView, OrientationHelper helper)
{
return helper.GetDecoratedStart(targetView) - helper.StartAfterPadding;
}
public override View FindSnapView(RecyclerView.LayoutManager layoutManager)
{
if (layoutManager is LinearLayoutManager) {
if (layoutManager.CanScrollHorizontally())
{
return getStartView(layoutManager, getHorizontalHelper(layoutManager));
}
else
{
return getStartView(layoutManager, getVerticalHelper(layoutManager));
}
}
return base.FindSnapView(layoutManager);
}
private View getStartView(RecyclerView.LayoutManager layoutManager,
OrientationHelper helper)
{
if (layoutManager is LinearLayoutManager) {
int firstChild = ((LinearLayoutManager)layoutManager).FindFirstVisibleItemPosition();
bool isLastItem = ((LinearLayoutManager)layoutManager)
.FindLastCompletelyVisibleItemPosition()
== layoutManager.ItemCount - 1;
if (firstChild == RecyclerView.NoPosition || isLastItem)
{
return null;
}
View child = layoutManager.FindViewByPosition(firstChild);
if (helper.GetDecoratedEnd(child) >= helper.GetDecoratedMeasurement(child) / 2
&& helper.GetDecoratedEnd(child) > 0)
{
return child;
}
else
{
if (((LinearLayoutManager)layoutManager).FindLastCompletelyVisibleItemPosition()
== layoutManager.ItemCount - 1)
{
return null;
}
else
{
return layoutManager.FindViewByPosition(firstChild + 1);
}
}
}
return base.FindSnapView(layoutManager);
}
private OrientationHelper getVerticalHelper(RecyclerView.LayoutManager layoutManager)
{
if (mVerticalHelper == null)
{
mVerticalHelper = OrientationHelper.CreateVerticalHelper(layoutManager);
}
return mVerticalHelper;
}
private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager)
{
if (mHorizontalHelper == null)
{
mHorizontalHelper = OrientationHelper.CreateHorizontalHelper(layoutManager);
}
return mHorizontalHelper;
}
}
And use like this:
SnapHelper snapHelperStart = new StartSnapHelper();
snapHelperStart.AttachToRecyclerView(recyclerView);

Undefined variable in my Yii2 Model

There is an error Undefined Variable when running my Model Class:
public $accountTypeFlag;
.......
public function getSecondType() {
if (($this->$accountTypeFlag == 1)){
return array (self::CURRENT_ASSETS=>'Current Assets',self::PROPERTY_AND_EQUIPMENT=>'Property and Equipment',self::OTHER_ASSETS=>'Other Assets');
}
if (($accountTypeFlag == 2)){
return array (self::CURRENT_LIABILITIES=>'Current Liabilities');
}
if (($accountTypeFlag == 3)){
return array (self::FUND_BALANCE=>'Fund Balance');
}
}
Is there any way to read the accountTypeFlag inside the function?
public $accountTypeFlag;
...
public function getSecondType() {
if ($this->accountTypeFlag == 1) {
...
} elseif ($this->accountTypeFlag == 2) {
...
} elseif ($this->accountTypeFlag == 3) {
...
}
}